LTP GCOV extension - code coverage report
Current view: directory - odbc - native.c
Test: FreeTDS coverage
Date: 2008-11-21 Instrumented lines: 130
Code covered: 80.8 % Executed lines: 105

       1                 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2                 :  * Copyright (C) 1998-2002  Brian Bruns
       3                 :  * Copyright (C) 2004, 2005 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                 : #if HAVE_CONFIG_H
      22                 : #include <config.h>
      23                 : #endif
      24                 : 
      25                 : #if HAVE_STDLIB_H
      26                 : #include <stdlib.h>
      27                 : #endif /* HAVE_STDLIB_H */
      28                 : 
      29                 : #if HAVE_STRING_H
      30                 : #include <string.h>
      31                 : #endif /* HAVE_STRING_H */
      32                 : 
      33                 : #if HAVE_ERRNO_H
      34                 : #include <errno.h>
      35                 : #endif /* HAVE_ERRNO_H */
      36                 : 
      37                 : #include <ctype.h>
      38                 : #include <assert.h>
      39                 : 
      40                 : #include "tdsodbc.h"
      41                 : 
      42                 : #ifdef DMALLOC
      43                 : #include <dmalloc.h>
      44                 : #endif
      45                 : 
      46                 : TDS_RCSID(var, "$Id: native.c,v 1.28.2.1 2006/03/21 12:24:48 freddy77 Exp $");
      47                 : 
      48                 : #define TDS_ISSPACE(c) isspace((unsigned char) (c))
      49                 : #define TDS_ISALPHA(c) isalpha((unsigned char) (c))
      50                 : 
      51                 : /*
      52                 :  * Function transformation (from ODBC to Sybase)
      53                 :  * String functions
      54                 :  * ASCII(string) -> ASCII(string)
      55                 :  * BIT_LENGTH(string) -> 8*OCTET_LENGTH(string)
      56                 :  * CHAR_LENGTH(string_exp) -> CHAR_LENGTH(string_exp)
      57                 :  * CHARACTER_LENGTH(string_exp) -> CHAR_LENGTH(string_exp)
      58                 :  * CONCAT(string_exp1, string_exp2) -> string_exp1 + string_exp2
      59                 :  * DIFFERENCE(string_exp1, string_exp2) -> DIFFERENCE(string_exp1, string_exp2)
      60                 :  * INSERT(string_exp1, start, length, string_exp2) -> STUFF(sameparams)
      61                 :  * LCASE(string_exp) -> LOWER(string)
      62                 :  * LEFT(string_exp, count) -> SUBSTRING(string, 1, count)
      63                 :  * LENGTH(string_exp) -> CHAR_LENGTH(RTRIM(string_exp))
      64                 :  * LOCATE(string, string [,start]) -> CHARINDEX(string, string)
      65                 :  * (SQLGetInfo should return third parameter not possible)
      66                 :  * LTRIM(String) -> LTRIM(String)
      67                 :  * OCTET_LENGTH(string_exp) -> OCTET_LENGTH(string_exp)
      68                 :  * POSITION(character_exp IN character_exp) ???
      69                 :  * REPEAT(string_exp, count) -> REPLICATE(same)
      70                 :  * REPLACE(string_exp1, string_exp2, string_exp3) -> ??
      71                 :  * RIGHT(string_exp, count) -> RIGHT(string_exp, count)
      72                 :  * RTRIM(string_exp) -> RTRIM(string_exp)
      73                 :  * SOUNDEX(string_exp) -> SOUNDEX(string_exp)
      74                 :  * SPACE(count) (ODBC 2.0) -> SPACE(count) (ODBC 2.0)
      75                 :  * SUBSTRING(string_exp, start, length) -> SUBSTRING(string_exp, start, length)
      76                 :  * UCASE(string_exp) -> UPPER(string)
      77                 :  *
      78                 :  * Numeric
      79                 :  * Nearly all function use same parameters, except:
      80                 :  * ATAN2 -> ATN2
      81                 :  * TRUNCATE -> ??
      82                 :  */
      83                 : static SQLRETURN
      84                 : to_native(struct _hdbc *dbc, struct _hstmt *stmt, char *buf)
      85             739 : {
      86                 :         char *d, *s;
      87             739 :         int nest_syntax = 0;
      88                 : 
      89                 :         /* list of bit, used as stack, is call ? FIXME limites size... */
      90             739 :         unsigned long is_calls = 0;
      91                 :         int server_scalar;
      92                 : 
      93             739 :         assert(dbc && buf);
      94                 : 
      95             739 :         server_scalar = TDS_IS_MSSQL(dbc->tds_socket) && dbc->tds_socket->product_version >= TDS_MS_VER(7, 0, 0);
      96                 : 
      97                 :         /*
      98                 :          * we can do it because result string will be
      99                 :          * not bigger than source string
     100                 :          */
     101             739 :         d = s = buf;
     102           33242 :         while (*s) {
     103                 :                 /* TODO: test syntax like "select 1 as [pi]]p)p{?=call]]]]o], 2" on mssql7+ */
     104           31764 :                 if (*s == '"' || *s == '\'' || *s == '[') {
     105             301 :                         size_t len_quote = tds_skip_quoted(s) - s;
     106                 : 
     107             301 :                         memmove(d, s, len_quote);
     108             301 :                         s += len_quote;
     109             301 :                         d += len_quote;
     110             301 :                         continue;
     111                 :                 }
     112                 : 
     113           31463 :                 if (*s == '{') {
     114                 :                         char *pcall;
     115                 : 
     116              41 :                         while (TDS_ISSPACE(*++s));
     117              33 :                         pcall = s;
     118                 :                         /* FIXME if nest_syntax > 0 problems */
     119              33 :                         if (server_scalar && strncasecmp(pcall, "fn ", 3) == 0) {
     120               0 :                                 *d++ = '{';
     121               0 :                                 continue;
     122                 :                         }
     123              33 :                         if (*pcall == '?') {
     124                 :                                 /* skip spaces after ? */
     125              24 :                                 while (TDS_ISSPACE(*++pcall));
     126              16 :                                 if (*pcall == '=') {
     127              20 :                                         while (TDS_ISSPACE(*++pcall));
     128                 :                                 } else {
     129                 :                                         /* avoid {?call ... syntax */
     130               0 :                                         pcall = s;
     131                 :                                 }
     132                 :                         }
     133              33 :                         if (strncasecmp(pcall, "call ", 5) != 0)
     134               0 :                                 pcall = NULL;
     135                 : 
     136              33 :                         if (stmt)
     137              33 :                                 stmt->prepared_query_is_rpc = 1;
     138              33 :                         ++nest_syntax;
     139              33 :                         is_calls <<= 1;
     140              33 :                         if (!pcall) {
     141                 :                                 /* assume syntax in the form {type ...} */
     142               0 :                                 while (TDS_ISALPHA(*s))
     143               0 :                                         ++s;
     144               0 :                                 while (TDS_ISSPACE(*s))
     145               0 :                                         ++s;
     146                 :                         } else {
     147              33 :                                 if (*s == '?' && stmt)
     148              16 :                                         stmt->prepared_query_is_func = 1;
     149              33 :                                 memcpy(d, "exec ", 5);
     150              33 :                                 d += 5;
     151              33 :                                 s = pcall + 5;
     152              33 :                                 is_calls |= 1;
     153                 :                         }
     154           31430 :                 } else if (nest_syntax > 0) {
     155                 :                         /* do not copy close syntax */
     156             597 :                         if (*s == '}') {
     157              33 :                                 --nest_syntax;
     158              33 :                                 is_calls >>= 1;
     159              33 :                                 ++s;
     160              33 :                                 continue;
     161                 :                                 /* convert parenthesis in call to spaces */
     162             630 :                         } else if ((is_calls & 1) && (*s == '(' || *s == ')')) {
     163              66 :                                 *d++ = ' ';
     164              66 :                                 s++;
     165                 :                         } else {
     166             498 :                                 *d++ = *s++;
     167                 :                         }
     168                 :                 } else {
     169           30833 :                         *d++ = *s++;
     170                 :                 }
     171                 :         }
     172             739 :         *d = '\0';
     173             739 :         return SQL_SUCCESS;
     174                 : }
     175                 : 
     176                 : const char *
     177                 : parse_const_param(const char *s, TDS_SERVER_TYPE *type)
     178              32 : {
     179                 :         char *end;
     180                 : 
     181                 :         /* binary */
     182              32 :         if (strncasecmp(s, "0x", 2) == 0) {
     183               4 :                 s += 2;
     184              72 :                 while (isxdigit(*s))
     185              64 :                         ++s;
     186               4 :                 *type = SYBVARBINARY;
     187               4 :                 return s;
     188                 :         }
     189                 : 
     190                 :         /* string */
     191              28 :         if (*s == '\'') {
     192              20 :                 *type = SYBVARCHAR;
     193              20 :                 return tds_skip_quoted(s);
     194                 :         }
     195                 : 
     196                 :         /* integer/float */
     197               8 :         if (isdigit(*s) || *s == '+' || *s == '-') {
     198               8 :                 errno = 0;
     199               8 :                 strtod(s, &end);
     200               8 :                 if (end != s && strcspn(s, ".eE") < (end-s)&& errno == 0) {
     201               4 :                         *type = SYBFLT8;
     202               4 :                         return end;
     203                 :                 }
     204               4 :                 errno = 0;
     205                 :                 /* FIXME success if long is 64bit */
     206               4 :                 strtol(s, &end, 10);
     207               4 :                 if (end != s && errno == 0) {
     208               4 :                         *type = SYBINT4;
     209               4 :                         return end;
     210                 :                 }
     211                 :         }
     212                 : 
     213                 :         /* TODO date, time */
     214                 : 
     215               0 :         return NULL;
     216                 : }
     217                 : 
     218                 : SQLRETURN
     219                 : prepare_call(struct _hstmt * stmt)
     220             739 : {
     221                 :         const char *s, *p, *param_start;
     222                 :         char *buf;
     223                 :         SQLRETURN rc;
     224                 :         TDS_SERVER_TYPE type;
     225                 : 
     226             739 :         if (stmt->prepared_query)
     227              97 :                 buf = stmt->prepared_query;
     228             642 :         else if (stmt->query)
     229             642 :                 buf = stmt->query;
     230                 :         else
     231               0 :                 return SQL_ERROR;
     232                 : 
     233             739 :         if ((rc = to_native(stmt->dbc, stmt, buf)) != SQL_SUCCESS)
     234               0 :                 return rc;
     235                 : 
     236                 :         /* now detect RPC */
     237             739 :         if (stmt->prepared_query_is_rpc == 0)
     238             706 :                 return SQL_SUCCESS;
     239              33 :         stmt->prepared_query_is_rpc = 0;
     240                 : 
     241              33 :         s = buf;
     242              66 :         while (TDS_ISSPACE(*s))
     243               0 :                 ++s;
     244              33 :         if (strncasecmp(s, "exec", 4) == 0) {
     245              33 :                 if (TDS_ISSPACE(s[4]))
     246              33 :                         s += 5;
     247               0 :                 else if (strncasecmp(s, "execute", 7) == 0 && TDS_ISSPACE(s[7]))
     248               0 :                         s += 8;
     249                 :                 else {
     250               0 :                         stmt->prepared_query_is_func = 0;
     251               0 :                         return SQL_SUCCESS;
     252                 :                 }
     253                 :         }
     254              66 :         while (TDS_ISSPACE(*s))
     255               0 :                 ++s;
     256              33 :         p = s;
     257              33 :         if (*s == '[') {
     258                 :                 /* FIXME handle [dbo].[name] and [master]..[name] syntax */
     259               0 :                 s = (char *) tds_skip_quoted(s);
     260                 :         } else {
     261                 :                 /* FIXME: stop at other characters ??? */
     262             409 :                 while (*s && !TDS_ISSPACE(*s))
     263             343 :                         ++s;
     264                 :         }
     265              33 :         param_start = s;
     266              33 :         --s;                    /* trick, now s point to no blank */
     267                 :         for (;;) {
     268             118 :                 while (TDS_ISSPACE(*++s));
     269              67 :                 if (!*s)
     270               0 :                         break;
     271              67 :                 switch (*s) {
     272                 :                 case '?':
     273              49 :                         break;
     274                 :                 case ',':
     275               2 :                         --s;
     276               2 :                         break;
     277                 :                 default:
     278              16 :                         if (!(s = parse_const_param(s, &type))) {
     279               0 :                                 stmt->prepared_query_is_func = 0;
     280               0 :                                 return SQL_SUCCESS;
     281                 :                         }
     282              16 :                         --s;
     283                 :                         break;
     284                 :                 }
     285             100 :                 while (TDS_ISSPACE(*++s));
     286              67 :                 if (!*s)
     287              33 :                         break;
     288              34 :                 if (*s != ',') {
     289               0 :                         stmt->prepared_query_is_func = 0;
     290               0 :                         return SQL_SUCCESS;
     291                 :                 }
     292              34 :         }
     293              33 :         stmt->prepared_query_is_rpc = 1;
     294                 : 
     295                 :         /* remove unneeded exec */
     296              33 :         memmove(buf, p, strlen(p) + 1);
     297              33 :         stmt->prepared_pos = buf + (param_start - p);
     298                 : 
     299              33 :         return SQL_SUCCESS;
     300                 : }
     301                 : 
     302                 : /* TODO handle output parameter and not terminated string */
     303                 : SQLRETURN
     304                 : native_sql(struct _hdbc * dbc, char *s)
     305               0 : {
     306               0 :         return to_native(dbc, NULL, s);
     307                 : }
     308                 : 
     309                 : /* function info */
     310                 : struct func_info;
     311                 : struct native_info;
     312                 : typedef void (*special_fn) (struct native_info * ni, struct func_info * fi, char **params);
     313                 : 
     314                 : struct func_info
     315                 : {
     316                 :         const char *name;
     317                 :         int num_param;
     318                 :         const char *sql_name;
     319                 :         special_fn special;
     320                 : };
     321                 : 
     322                 : struct native_info
     323                 : {
     324                 :         char *d;
     325                 :         int length;
     326                 : };
     327                 : 
     328                 : #if 0                           /* developing ... */
     329                 : 
     330                 : #define MAX_PARAMS 4
     331                 : 
     332                 : static const struct func_info funcs[] = {
     333                 :         /* string functions */
     334                 :         {"ASCII", 1},
     335                 :         {"BIT_LENGTH", 1, "(8*OCTET_LENGTH", fn_parentheses},
     336                 :         {"CHAR", 1},
     337                 :         {"CHAR_LENGTH", 1},
     338                 :         {"CHARACTER_LENGTH", 1, "CHAR_LENGTH"},
     339                 :         {"CONCAT", 2, NULL, fn_concat},       /* a,b -> a+b */
     340                 :         {"DIFFERENCE", 2},
     341                 :         {"INSERT", 4, "STUFF"},
     342                 :         {"LCASE", 1, "LOWER"},
     343                 :         {"LEFT", 2, "SUBSTRING", fn_left},
     344                 :         {"LENGTH", 1, "CHAR_LENGTH(RTRIM", fn_parentheses},
     345                 :         {"LOCATE", 2, "CHARINDEX"},
     346                 : /* (SQLGetInfo should return third parameter not possible) */
     347                 :         {"LTRIM", 1},
     348                 :         {"OCTET_LENGTH", 1},
     349                 : /*       POSITION(character_exp IN character_exp) */
     350                 :         {"REPEAT", 2, "REPLICATE"},
     351                 : /*       REPLACE(string_exp1, string_exp2, string_exp3) */
     352                 :         {"RIGHT", 2},
     353                 :         {"RTRIM", 1},
     354                 :         {"SOUNDEX", 1},
     355                 :         {"SPACE", 1},
     356                 :         {"SUBSTRING", 3},
     357                 :         {"UCASE", 1, "UPPER"},
     358                 : 
     359                 :         /* numeric functions */
     360                 :         {"ABS", 1},
     361                 :         {"ACOS", 1},
     362                 :         {"ASIN", 1},
     363                 :         {"ATAN", 1},
     364                 :         {"ATAN2", 2, "ATN2"},
     365                 :         {"CEILING", 1},
     366                 :         {"COS", 1},
     367                 :         {"COT", 1},
     368                 :         {"DEGREES", 1},
     369                 :         {"EXP", 1},
     370                 :         {"FLOOR", 1},
     371                 :         {"LOG", 1},
     372                 :         {"LOG10", 1},
     373                 :         {"MOD", 2, NULL, fn_mod},     /* mod(a,b) -> ((a)%(b)) */
     374                 :         {"PI", 0},
     375                 :         {"POWER", 2},
     376                 :         {"RADIANS", 1},
     377                 :         {"RAND", -1, NULL, fn_rand},  /* accept 0 or 1 parameters */
     378                 :         {"ROUND", 2},
     379                 :         {"SIGN", 1},
     380                 :         {"SIN", 1},
     381                 :         {"SQRT", 1},
     382                 :         {"TAN", 1},
     383                 : /*       TRUNCATE(numeric_exp, integer_exp) */
     384                 : 
     385                 :         /* system functions */
     386                 :         {"DATABASE", 0, "DB_NAME"},
     387                 :         {"IFNULL", 2, "ISNULL"},
     388                 :         {"USER", 0, "USER_NAME"}
     389                 : 
     390                 : };
     391                 : 
     392                 : /**
     393                 :  * Parse given sql and return converted sql
     394                 :  */
     395                 : int
     396                 : odbc_native_sql(const char *odbc_sql, char **out)
     397                 : {
     398                 :         char *d;
     399                 : }
     400                 : 
     401                 : #endif

Generated by: LTP GCOV extension version 1.6