Line data Source code
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/utils/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 24170 : to_native(struct _hdbc *dbc, struct _hstmt *stmt, DSTR *str)
78 : {
79 : char *d, *s;
80 24170 : int nest_syntax = 0;
81 48340 : char *buf = tds_dstr_buf(str);
82 :
83 : /* list of bit, used as stack, is call ? FIXME limites size... */
84 24170 : unsigned long is_calls = 0;
85 : int server_scalar;
86 :
87 24170 : assert(dbc);
88 :
89 24170 : 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 24170 : d = s = buf;
96 1030696 : while (*s) {
97 982356 : if (*s == '-' || *s == '/') {
98 92 : size_t len_comment = tds_skip_comment(s) - s;
99 :
100 92 : memmove(d, s, len_comment);
101 92 : s += len_comment;
102 92 : d += len_comment;
103 92 : continue;
104 : }
105 :
106 : /* TODO: test syntax like "select 1 as [pi]]p)p{?=call]]]]o], 2" on mssql7+ */
107 982264 : if (*s == '"' || *s == '\'' || *s == '[') {
108 9579 : size_t len_quote = tds_skip_quoted(s) - s;
109 :
110 9579 : memmove(d, s, len_quote);
111 9579 : s += len_quote;
112 9579 : d += len_quote;
113 9579 : continue;
114 : }
115 :
116 972685 : if (*s == '{') {
117 : char *pcall;
118 :
119 780 : while (TDS_ISSPACE(*++s))
120 52 : continue;
121 728 : pcall = s;
122 : /* FIXME if nest_syntax > 0 problems */
123 728 : if (server_scalar && strncasecmp(pcall, "fn ", 3) == 0) {
124 0 : *d++ = '{';
125 0 : continue;
126 : }
127 728 : if (*pcall == '?') {
128 : /* skip spaces after ? */
129 196 : while (TDS_ISSPACE(*++pcall))
130 46 : continue;
131 150 : if (*pcall == '=') {
132 180 : while (TDS_ISSPACE(*++pcall))
133 30 : continue;
134 : } else {
135 : /* avoid {?call ... syntax */
136 : pcall = s;
137 : }
138 : }
139 728 : if (strncasecmp(pcall, "call ", 5) != 0)
140 0 : pcall = NULL;
141 :
142 728 : if (stmt)
143 728 : stmt->prepared_query_is_rpc = 1;
144 728 : ++nest_syntax;
145 728 : is_calls <<= 1;
146 728 : if (!pcall) {
147 : /* assume syntax in the form {type ...} */
148 0 : while (TDS_ISALPHA(*s))
149 0 : ++s;
150 0 : while (TDS_ISSPACE(*s))
151 0 : ++s;
152 : } else {
153 728 : if (*s == '?' && stmt)
154 150 : stmt->prepared_query_is_func = 1;
155 728 : memcpy(d, "exec ", 5);
156 728 : d += 5;
157 728 : s = pcall + 5;
158 728 : is_calls |= 1;
159 : }
160 971957 : } else if (nest_syntax > 0) {
161 : /* do not copy close syntax */
162 11192 : if (*s == '}') {
163 728 : --nest_syntax;
164 728 : is_calls >>= 1;
165 728 : ++s;
166 728 : continue;
167 : /* convert parenthesis in call to spaces */
168 10464 : } else if ((is_calls & 1) && (*s == '(' || *s == ')')) {
169 1444 : *d++ = ' ';
170 1444 : s++;
171 : } else {
172 9020 : *d++ = *s++;
173 : }
174 : } else {
175 960765 : *d++ = *s++;
176 : }
177 : }
178 24170 : tds_dstr_setlen(str, d - buf);
179 24170 : return SQL_SUCCESS;
180 : }
181 :
182 : const char *
183 144 : parse_const_param(const char *s, TDS_SERVER_TYPE *type)
184 : {
185 : char *end;
186 :
187 : /* binary */
188 144 : if (strncasecmp(s, "0x", 2) == 0) {
189 16 : s += 2;
190 288 : while (isxdigit(*s))
191 256 : ++s;
192 16 : *type = SYBVARBINARY;
193 16 : return s;
194 : }
195 :
196 : /* string */
197 128 : if (*s == '\'') {
198 80 : *type = SYBVARCHAR;
199 80 : return tds_skip_quoted(s);
200 : }
201 :
202 : /* integer/float */
203 48 : if (isdigit(*s) || *s == '+' || *s == '-') {
204 : long val;
205 :
206 48 : errno = 0;
207 48 : strtod(s, &end);
208 48 : if (end != s && strcspn(s, ".eE") < (size_t) (end-s) && errno == 0) {
209 16 : *type = SYBFLT8;
210 16 : return end;
211 : }
212 32 : errno = 0;
213 :
214 32 : val = strtol(s, &end, 10);
215 32 : if (end != s && errno == 0) {
216 32 : if (val+1 >= -0x7FFFFFFF && val <= 0x7FFFFFFF)
217 16 : *type = SYBINT4;
218 : else
219 16 : *type = SYBINT8;
220 : return end;
221 : }
222 :
223 0 : errno = 0;
224 0 : tds_strtoll(s, &end, 10);
225 0 : if (end != s && errno == 0) {
226 0 : *type = SYBINT8;
227 0 : return end;
228 : }
229 : }
230 :
231 : /* TODO date, time */
232 :
233 : return NULL;
234 : }
235 :
236 : const char *
237 1590 : odbc_skip_rpc_name(const char *s)
238 : {
239 17504 : for (;*s; ++s) {
240 17342 : if (*s == '[') {
241 : /* handle [dbo].[name] and [master]..[name] syntax */
242 24 : s = tds_skip_quoted(s);
243 24 : if (*s != '.')
244 : break;
245 17318 : } else if (TDS_ISSPACE(*s)) {
246 : /* FIXME: stop at other characters ??? */
247 : break;
248 : }
249 : }
250 1590 : return s;
251 : }
252 :
253 : SQLRETURN
254 24170 : prepare_call(struct _hstmt * stmt)
255 : {
256 : const char *s, *p, *param_start;
257 : char *buf;
258 : SQLRETURN rc;
259 : TDS_SERVER_TYPE type;
260 :
261 48340 : if (tds_dstr_isempty(&stmt->query))
262 : return SQL_ERROR;
263 :
264 72508 : if ((!tds_dstr_isempty(&stmt->attr.qn_msgtext) || !tds_dstr_isempty(&stmt->attr.qn_options))
265 2 : && !IS_TDS72_PLUS(stmt->dbc->tds_socket->conn)) {
266 0 : odbc_errs_add(&stmt->errs, "HY000", "Feature is not supported by this server");
267 0 : return SQL_SUCCESS_WITH_INFO;
268 : }
269 :
270 24170 : if ((rc = to_native(stmt->dbc, stmt, &stmt->query)) != SQL_SUCCESS)
271 : return rc;
272 :
273 : /* now detect RPC */
274 24170 : if (stmt->prepared_query_is_rpc == 0)
275 : return SQL_SUCCESS;
276 728 : stmt->prepared_query_is_rpc = 0;
277 :
278 1456 : s = buf = tds_dstr_buf(&stmt->query);
279 1456 : while (TDS_ISSPACE(*s))
280 0 : ++s;
281 728 : if (strncasecmp(s, "exec", 4) == 0) {
282 728 : if (TDS_ISSPACE(s[4]))
283 728 : s += 5;
284 0 : else if (strncasecmp(s, "execute", 7) == 0 && TDS_ISSPACE(s[7]))
285 0 : s += 8;
286 : else {
287 0 : stmt->prepared_query_is_func = 0;
288 0 : return SQL_SUCCESS;
289 : }
290 : }
291 728 : while (TDS_ISSPACE(*s))
292 0 : ++s;
293 728 : p = s;
294 728 : s = (char *) odbc_skip_rpc_name(s);
295 728 : param_start = s;
296 728 : --s; /* trick, now s point to no blank */
297 : for (;;) {
298 1868 : while (TDS_ISSPACE(*++s))
299 830 : continue;
300 1038 : if (!*s)
301 : break;
302 1032 : switch (*s) {
303 : case '?':
304 : break;
305 8 : case ',':
306 8 : --s;
307 8 : break;
308 72 : default:
309 72 : if (!(s = parse_const_param(s, &type))) {
310 0 : stmt->prepared_query_is_func = 0;
311 0 : return SQL_SUCCESS;
312 : }
313 72 : --s;
314 72 : break;
315 : }
316 1776 : while (TDS_ISSPACE(*++s))
317 744 : continue;
318 1032 : if (!*s)
319 : break;
320 310 : if (*s != ',') {
321 0 : stmt->prepared_query_is_func = 0;
322 0 : return SQL_SUCCESS;
323 : }
324 : }
325 728 : stmt->prepared_query_is_rpc = 1;
326 :
327 : /* remove unneeded exec */
328 728 : s += strlen(s);
329 728 : memmove(buf, p, s - p);
330 728 : tds_dstr_setlen(&stmt->query, s - p);
331 728 : stmt->prepared_pos = param_start - p;
332 :
333 728 : return SQL_SUCCESS;
334 : }
335 :
336 : /* TODO handle output parameter and not terminated string */
337 : SQLRETURN
338 0 : native_sql(struct _hdbc * dbc, DSTR *s)
339 : {
340 0 : return to_native(dbc, NULL, s);
341 : }
342 :
343 : /* function info */
344 : struct func_info;
345 : struct native_info;
346 : typedef void (*special_fn) (struct native_info * ni, struct func_info * fi, char **params);
347 :
348 : struct func_info
349 : {
350 : const char *name;
351 : int num_param;
352 : const char *sql_name;
353 : special_fn special;
354 : };
355 :
356 : struct native_info
357 : {
358 : char *d;
359 : int length;
360 : };
361 :
362 : #if 0 /* developing ... */
363 :
364 : #define MAX_PARAMS 4
365 :
366 : static const struct func_info funcs[] = {
367 : /* string functions */
368 : {"ASCII", 1},
369 : {"BIT_LENGTH", 1, "(8*OCTET_LENGTH", fn_parentheses},
370 : {"CHAR", 1},
371 : {"CHAR_LENGTH", 1},
372 : {"CHARACTER_LENGTH", 1, "CHAR_LENGTH"},
373 : {"CONCAT", 2, NULL, fn_concat}, /* a,b -> a+b */
374 : {"DIFFERENCE", 2},
375 : {"INSERT", 4, "STUFF"},
376 : {"LCASE", 1, "LOWER"},
377 : {"LEFT", 2, "SUBSTRING", fn_left},
378 : {"LENGTH", 1, "CHAR_LENGTH(RTRIM", fn_parentheses},
379 : {"LOCATE", 2, "CHARINDEX"},
380 : /* (SQLGetInfo should return third parameter not possible) */
381 : {"LTRIM", 1},
382 : {"OCTET_LENGTH", 1},
383 : /* POSITION(character_exp IN character_exp) */
384 : {"REPEAT", 2, "REPLICATE"},
385 : /* REPLACE(string_exp1, string_exp2, string_exp3) */
386 : {"RIGHT", 2},
387 : {"RTRIM", 1},
388 : {"SOUNDEX", 1},
389 : {"SPACE", 1},
390 : {"SUBSTRING", 3},
391 : {"UCASE", 1, "UPPER"},
392 :
393 : /* numeric functions */
394 : {"ABS", 1},
395 : {"ACOS", 1},
396 : {"ASIN", 1},
397 : {"ATAN", 1},
398 : {"ATAN2", 2, "ATN2"},
399 : {"CEILING", 1},
400 : {"COS", 1},
401 : {"COT", 1},
402 : {"DEGREES", 1},
403 : {"EXP", 1},
404 : {"FLOOR", 1},
405 : {"LOG", 1},
406 : {"LOG10", 1},
407 : {"MOD", 2, NULL, fn_mod}, /* mod(a,b) -> ((a)%(b)) */
408 : {"PI", 0},
409 : {"POWER", 2},
410 : {"RADIANS", 1},
411 : {"RAND", -1, NULL, fn_rand}, /* accept 0 or 1 parameters */
412 : {"ROUND", 2},
413 : {"SIGN", 1},
414 : {"SIN", 1},
415 : {"SQRT", 1},
416 : {"TAN", 1},
417 : /* TRUNCATE(numeric_exp, integer_exp) */
418 :
419 : /* system functions */
420 : {"DATABASE", 0, "DB_NAME"},
421 : {"IFNULL", 2, "ISNULL"},
422 : {"USER", 0, "USER_NAME"}
423 :
424 : };
425 :
426 : /**
427 : * Parse given sql and return converted sql
428 : */
429 : int
430 : odbc_native_sql(const char *odbc_sql, char **out)
431 : {
432 : char *d;
433 : }
434 :
435 : #endif
|