LCOV - code coverage report
Current view: top level - src/server - query.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 45 104 43.3 %
Date: 2025-01-18 11:50:39 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-2004  Brian Bruns
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : #include <config.h>
      20             : 
      21             : #include <assert.h>
      22             : 
      23             : #if HAVE_STDLIB_H
      24             : #include <stdlib.h>
      25             : #endif /* HAVE_STDLIB_H */
      26             : 
      27             : #include <freetds/tds.h>
      28             : #include <freetds/server.h>
      29             : 
      30             : static char *query;
      31             : static size_t query_buflen = 0;
      32             : static TDSHEADERS head;
      33             : 
      34             : /**
      35             :  * Read a TDS5 tokenized query.
      36             :  */
      37             : char *
      38           0 : tds_get_query(TDSSOCKET * tds)
      39             : {
      40             :         int len;
      41             : 
      42           0 :         if (query_buflen == 0) {
      43           0 :                 query_buflen = 1024;
      44           0 :                 query = tds_new(char, query_buflen);
      45             :         }
      46           0 :         tds_get_byte(tds);      /* 33 */
      47           0 :         len = tds_get_int(tds); /* query size +1 */
      48           0 :         tds_get_byte(tds);      /* has args, ignored TODO */
      49           0 :         assert(len >= 1);    /* TODO handle correctly */
      50           0 :         if (len > query_buflen) {
      51           0 :                 query_buflen = len;
      52           0 :                 query = (char *) realloc(query, query_buflen);
      53             :         }
      54           0 :         --len;
      55           0 :         tds_get_n(tds, query, len);
      56           0 :         query[len] = 0;
      57           0 :         return query;
      58             : }
      59             : 
      60             : static bool
      61             : tds_lastpacket(TDSSOCKET * tds) 
      62             : {
      63         208 :         if (!tds || !tds->in_buf || tds->recv_packet->capacity < 2)
      64             :                 return true;
      65             :         
      66         208 :         return tds->in_buf[1] != 0;
      67             : }
      68             : 
      69             : /**
      70             :  * get query packet of a given type
      71             :  * \tds
      72             :  * \param head         extra information to put in a TDS7 header
      73             :  */
      74             : static TDSRET
      75         208 : tds_get_query_head(TDSSOCKET * tds, TDSHEADERS * head)
      76             : {
      77         208 :         int qn_len = 0, more;
      78         208 :         char *qn_msgtext = NULL;
      79         208 :         char *qn_options = NULL;
      80         208 :         size_t qn_msgtext_len = 0;
      81         208 :         size_t qn_options_len = 0;
      82             : 
      83         208 :         if (!IS_TDS72_PLUS(tds->conn))
      84             :                 return TDS_SUCCESS;
      85             : 
      86         208 :         free((void *) head->qn_options);
      87         208 :         head->qn_options = NULL;
      88         208 :         free((void *) head->qn_msgtext);
      89         208 :         head->qn_msgtext = NULL;
      90             : 
      91         208 :         qn_len = tds_get_int(tds) - 4 - 18;  /* total length */
      92         208 :         tds_get_int(tds);  /* length: transaction descriptor, ignored */
      93         208 :         tds_get_smallint(tds);  /* type: transaction descriptor, ignored */
      94         208 :         tds_get_n(tds, tds->conn->tds72_transaction, 8);  /* transaction */
      95         208 :         tds_get_int(tds);  /* request count, ignored */
      96         208 :         if (qn_len != 0) {
      97           0 :                 qn_len = tds_get_int(tds);  /* length: query notification */
      98           0 :                 tds_get_smallint(tds);  /* type: query notification, ignored */
      99           0 :                 qn_msgtext_len = tds_get_smallint(tds);  /* notifyid */
     100           0 :                 if (qn_msgtext_len > 0) {
     101           0 :                         qn_msgtext = (char *) realloc(qn_msgtext, qn_msgtext_len);
     102           0 :                         tds_get_n(tds, qn_msgtext, qn_msgtext_len);
     103             :                 }
     104             : 
     105           0 :                 qn_options_len = tds_get_smallint(tds);  /* ssbdeployment */
     106           0 :                 if (qn_options_len > 0) {
     107           0 :                         qn_options = (char *) realloc(qn_options, qn_options_len);
     108           0 :                         tds_get_n(tds, qn_options, qn_options_len);
     109             :                 }
     110           0 :                 more = tds->in_len - tds->in_pos;
     111           0 :                 if (more)
     112           0 :                         head->qn_timeout = tds_get_int(tds);  /* timeout */
     113             : 
     114           0 :                 head->qn_options = qn_options;
     115           0 :                 head->qn_msgtext = qn_msgtext;
     116             :         }
     117             :         return TDS_SUCCESS;
     118             : }
     119             : 
     120             : /**
     121             :  * Read a query, and return it as an ASCII string with a \0 terminator.  This
     122             :  * should work for TDS4, TDS5, and TDS7+ connections.  Also, it converts RPC
     123             :  * calls into stored procedure queries, and it skips CANCEL packets.  The query
     124             :  * string is returned in a static buffer which is overwritten each time this
     125             :  * function is called.
     126             :  * \param tds  The socket to read from.
     127             :  * \return A query string if successful, or NULL if we either can't read from
     128             :  * the socket or we read something that we can't handle.
     129             :  */
     130             : char *
     131         224 : tds_get_generic_query(TDSSOCKET * tds)
     132             : {
     133             :         int token, byte;
     134             :         int len, more, i, j;
     135             : 
     136             :         for (;;) {
     137             :                 /*
     138             :                  * Read a new packet.  We must explicitly read it,
     139             :                  * instead of letting functions such as tds_get_byte()
     140             :                  * to read it for us, so that we can examine the packet
     141             :                  * type via tds->in_flag.
     142             :                  */
     143         224 :                 if (tds_read_packet(tds) < 0)
     144             :                         return NULL;
     145             : 
     146             :                 /* Queries can arrive in a couple different formats. */
     147         208 :                 switch (tds->in_flag) {
     148             :                 case TDS_RPC:
     149             :                         /* TODO */
     150             :                         return NULL;
     151           0 :                 case TDS_NORMAL: /* TDS5 query packet */
     152             :                         /* get the token */
     153           0 :                         token = tds_get_byte(tds);
     154           0 :                         switch (token) {
     155           0 :                         case TDS_LANGUAGE_TOKEN:
     156             :                                 /* SQL query */
     157           0 :                                 len = tds_get_int(tds); /* query size +1 */
     158           0 :                                 assert(len >= 1);    /* TODO handle */
     159           0 :                                 tds_get_byte(tds);      /* has args, ignored TODO */
     160           0 :                                 if (len > query_buflen) {
     161           0 :                                         query_buflen = len;
     162           0 :                                         query = (char *) realloc(query, query_buflen);
     163             :                                 }
     164           0 :                                 --len;
     165           0 :                                 tds_get_n(tds, query, len);
     166           0 :                                 query[len] = 0;
     167           0 :                                 return query;
     168             : 
     169           0 :                         case TDS_DBRPC_TOKEN:
     170             :                                 /* RPC call -- make it look like a query */
     171             : 
     172             :                                 /* skip the overall length */
     173           0 :                                 (void)tds_get_smallint(tds);
     174             : 
     175             :                                 /* get the length of the stored procedure's name */
     176           0 :                                 len = tds_get_byte(tds) + 1;/* sproc name size +1 */
     177           0 :                                 if (len > query_buflen) {
     178           0 :                                         query_buflen = len;
     179           0 :                                         query = (char *) realloc(query, query_buflen);
     180             :                                 }
     181             : 
     182             :                                 /*
     183             :                                  * Read the chars of the name.  Skip NUL
     184             :                                  * bytes, as a cheap way to convert
     185             :                                  * Unicode to ASCII.  (For TDS7+, the
     186             :                                  * name is sent in Unicode.)
     187             :                                  */
     188           0 :                                 for (i = j  = 0; i < len - 1; i++) {
     189           0 :                                         byte = tds_get_byte(tds);
     190           0 :                                         if (byte != '\0')
     191           0 :                                                 query[j++] = byte;
     192             :                                 }
     193           0 :                                 query[j] = '\0';
     194             : 
     195             :                                 /* TODO: WE DON'T HANDLE PARAMETERS YET! */
     196             : 
     197             :                                 /* eat the rest of the packet */
     198           0 :                                 while (!tds_lastpacket(tds) && tds_read_packet(tds) > 0) {
     199             :                                 }
     200           0 :                                 return query;
     201             : 
     202             :                         default:
     203             :                                 /* unexpected token */
     204             : 
     205             :                                 /* eat the rest of the packet */
     206           0 :                                 while (!tds_lastpacket(tds) && tds_read_packet(tds) > 0) {
     207             :                                 }
     208             :                                 return NULL;
     209             :                         }
     210             :                         break;
     211             : 
     212         208 :                 case TDS_QUERY:
     213             :                         /* TDS7+ adds a query head */
     214         208 :                         if (IS_TDS72_PLUS(tds->conn) && tds_get_query_head(tds, &head) != TDS_SUCCESS)
     215             :                                 return NULL;
     216             : 
     217             :                         /* TDS4 and TDS7+ fill the whole packet with a query */
     218             :                         len = 0;
     219             :                         for (;;) {
     220             :                                 const char *src;
     221             : 
     222             :                                 /* If buffer needs to grow, then grow */
     223         208 :                                 more = tds->in_len - tds->in_pos;
     224         208 :                                 src = (char *) (tds->in_buf + tds->in_pos);
     225         208 :                                 if ((size_t)(len + more + 1) > query_buflen) {
     226          16 :                                         query_buflen = len + more + 1024u;
     227          16 :                                         query_buflen -= query_buflen % 1024u;
     228          16 :                                         query = (char *) realloc(query, query_buflen);
     229             :                                 }
     230             : 
     231             :                                 /*
     232             :                                  * Pull new data into the query buffer.
     233             :                                  * Ignore NUL bytes -- this is a cheap way
     234             :                                  * to convert Unicode to Latin-1/ASCII.
     235             :                                  */
     236       16848 :                                 while (--more >= 0) {
     237       16640 :                                         query[len] = *src++;
     238       16640 :                                         if (query[len] != '\0')
     239        8320 :                                                 len++;
     240             :                                 }
     241             : 
     242             :                                 /* if more then read it */
     243         208 :                                 if (tds_lastpacket(tds))
     244             :                                         break;
     245           0 :                                 if (tds_read_packet(tds) < 0)
     246             :                                         return NULL;
     247             :                         }
     248             : 
     249             :                         /* add a NUL to mark the end */
     250         208 :                         query[len] = '\0';
     251         208 :                         return query;
     252             : 
     253             :                 case TDS_CANCEL:
     254             :                         /*
     255             :                          * ignore cancel requests -- if we're waiting
     256             :                          * for the next query then it's obviously too
     257             :                          * late to cancel the previous query.
     258             :                          */
     259             :                         /* TODO it's not too late -- freddy77 */
     260             :                         return NULL;
     261             : 
     262             :                 default:
     263             :                         /* not a query packet */
     264             :                         return NULL;
     265             :                 }
     266             :         }
     267             : }
     268             : 
     269             : /**
     270             :  * Free query buffer returned by tds_get_generic_query.
     271             :  */
     272             : void
     273          16 : tds_free_query(void)
     274             : {
     275          16 :         TDS_ZERO_FREE(query);
     276          16 :         query_buflen = 0;
     277             : 
     278          16 :         free((void *) head.qn_options);
     279          16 :         head.qn_options = NULL;
     280          16 :         free((void *) head.qn_msgtext);
     281          16 :         head.qn_msgtext = NULL;
     282          16 : }

Generated by: LCOV version 1.13