NCBI C++ ToolKit
native.c
Go to the documentation of this file.

Go to the SVN repository for this file.

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