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) 2005-2008 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 : #include <stdarg.h>
24 : #include <stdio.h>
25 : #include <assert.h>
26 :
27 : #if HAVE_STDLIB_H
28 : #include <stdlib.h>
29 : #endif /* HAVE_STDLIB_H */
30 :
31 : #if HAVE_STRING_H
32 : #include <string.h>
33 : #endif /* HAVE_STRING_H */
34 :
35 : #include <ctype.h>
36 :
37 : #include <freetds/odbc.h>
38 : #include <freetds/convert.h>
39 : #include <freetds/utils/string.h>
40 : #include <freetds/checks.h>
41 :
42 : #define TDS_ISSPACE(c) isspace((unsigned char) (c))
43 :
44 : static int
45 938 : prepared_rpc(struct _hstmt *stmt, bool compute_row)
46 : {
47 938 : int nparam = stmt->params ? stmt->params->num_cols : 0;
48 : const char *p;
49 938 : TDSCONNECTION *conn = stmt->dbc->tds_socket->conn;
50 :
51 1876 : if (stmt->prepared_pos > tds_dstr_len(&stmt->query))
52 : return SQL_ERROR;
53 :
54 1876 : p = tds_dstr_cstr(&stmt->query) + stmt->prepared_pos - 1;
55 :
56 400 : for (;;) {
57 : TDSPARAMINFO *temp_params;
58 : TDSCOLUMN *curcol;
59 : TDS_SERVER_TYPE type;
60 : const char *start;
61 :
62 2404 : while (TDS_ISSPACE(*++p))
63 1066 : continue;
64 1338 : if (!*p)
65 938 : return SQL_SUCCESS;
66 :
67 : /* we have certainly a parameter */
68 1330 : if (!(temp_params = tds_alloc_param_result(stmt->params))) {
69 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
70 0 : return SQL_ERROR;
71 : }
72 1330 : stmt->params = temp_params;
73 1330 : curcol = temp_params->columns[nparam];
74 :
75 1330 : switch (*p) {
76 10 : case ',':
77 10 : if (IS_TDS7_PLUS(conn)) {
78 8 : tds_set_param_type(conn, curcol, SYBVOID);
79 8 : curcol->column_size = curcol->column_cur_size = 0;
80 : } else {
81 : /* TODO is there a better type ? */
82 2 : tds_set_param_type(conn, curcol, SYBINTN);
83 2 : curcol->column_size = curcol->on_server.column_size = 4;
84 2 : curcol->column_cur_size = -1;
85 : }
86 10 : if (compute_row)
87 10 : if (!tds_alloc_param_data(curcol)) {
88 0 : tds_free_param_result(temp_params);
89 0 : return SQL_ERROR;
90 : }
91 : --p;
92 : break;
93 90 : default:
94 : /* add next parameter to list */
95 90 : start = p;
96 :
97 90 : if (!(p = parse_const_param(p, &type))) {
98 0 : tds_free_param_result(temp_params);
99 0 : return SQL_ERROR;
100 : }
101 90 : tds_set_param_type(conn, curcol, type);
102 90 : switch (type) {
103 50 : case SYBVARCHAR:
104 50 : curcol->column_size = p - start;
105 50 : break;
106 10 : case SYBVARBINARY:
107 10 : curcol->column_size = (p - start) / 2 -1;
108 10 : break;
109 : default:
110 0 : assert(0);
111 : case SYBINT4:
112 : case SYBINT8:
113 : case SYBFLT8:
114 30 : curcol->column_cur_size = curcol->column_size;
115 30 : break;
116 : }
117 90 : curcol->on_server.column_size = curcol->column_size;
118 : /* TODO support other type other than VARCHAR, do not strip escape in prepare_call */
119 90 : if (compute_row) {
120 : char *dest;
121 : int len;
122 : CONV_RESULT cr;
123 :
124 90 : if (!tds_alloc_param_data(curcol)) {
125 0 : tds_free_param_result(temp_params);
126 0 : return SQL_ERROR;
127 : }
128 90 : dest = (char *) curcol->column_data;
129 90 : switch (type) {
130 50 : case SYBVARCHAR:
131 50 : if (*start != '\'') {
132 0 : memcpy(dest, start, p - start);
133 0 : curcol->column_cur_size = p - start;
134 : } else {
135 50 : ++start;
136 : for (;;) {
137 1030 : if (*start == '\'')
138 50 : ++start;
139 540 : if (start >= p)
140 : break;
141 490 : *dest++ = *start++;
142 : }
143 50 : curcol->column_cur_size =
144 50 : dest - (char *) curcol->column_data;
145 : }
146 : break;
147 10 : case SYBVARBINARY:
148 10 : cr.cb.len = curcol->column_size;
149 10 : cr.cb.ib = dest;
150 10 : len = tds_convert(NULL, SYBVARCHAR, start, p - start, TDS_CONVERT_BINARY, &cr);
151 10 : if (len >= 0 && len <= curcol->column_size)
152 10 : curcol->column_cur_size = len;
153 : break;
154 10 : case SYBINT4:
155 10 : *((TDS_INT *) dest) = atoi(start);
156 10 : break;
157 10 : case SYBINT8:
158 10 : *((TDS_INT8 *) dest) = tds_strtoll(start, NULL, 10);
159 10 : break;
160 10 : case SYBFLT8:
161 10 : *((TDS_FLOAT *) dest) = strtod(start, NULL);
162 10 : break;
163 : default:
164 : break;
165 : }
166 : }
167 90 : --p;
168 90 : break;
169 1230 : case '?':
170 : /* find bound parameter */
171 1230 : if (stmt->param_num > stmt->apd->header.sql_desc_count
172 1230 : || stmt->param_num > stmt->ipd->header.sql_desc_count) {
173 0 : tds_free_param_result(temp_params);
174 : /* TODO set error */
175 0 : return SQL_ERROR;
176 : }
177 :
178 2460 : switch (odbc_sql2tds
179 1230 : (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
180 1230 : curcol, compute_row, stmt->apd, stmt->curr_param_row)) {
181 : case SQL_ERROR:
182 : return SQL_ERROR;
183 0 : case SQL_NEED_DATA:
184 0 : return SQL_NEED_DATA;
185 : }
186 1210 : ++stmt->param_num;
187 1210 : break;
188 : }
189 1310 : ++nparam;
190 :
191 3558 : while (TDS_ISSPACE(*++p))
192 938 : continue;
193 1310 : if (!*p || *p != ',')
194 : return SQL_SUCCESS;
195 800 : stmt->prepared_pos = p + 1 - tds_dstr_cstr(&stmt->query);
196 : }
197 : }
198 :
199 : int
200 33913 : parse_prepared_query(struct _hstmt *stmt, bool compute_row)
201 : {
202 : /* try setting this parameter */
203 : TDSPARAMINFO *temp_params;
204 33913 : int nparam = stmt->params ? stmt->params->num_cols : 0;
205 :
206 33913 : if (stmt->prepared_pos > 0)
207 938 : return prepared_rpc(stmt, compute_row);
208 :
209 32975 : tdsdump_log(TDS_DBG_FUNC, "parsing %d parameters\n", nparam);
210 :
211 7952 : for (; stmt->param_num <= (int) stmt->param_count; ++nparam, ++stmt->param_num) {
212 : /* find bound parameter */
213 8292 : if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count) {
214 8 : tdsdump_log(TDS_DBG_FUNC, "parse_prepared_query: logic_error: parameter out of bounds: "
215 : "%d > %d || %d > %d\n",
216 : stmt->param_num, stmt->apd->header.sql_desc_count,
217 0 : stmt->param_num, stmt->ipd->header.sql_desc_count);
218 : return SQL_ERROR;
219 : }
220 :
221 : /* add a column to parameters */
222 8284 : if (!(temp_params = tds_alloc_param_result(stmt->params))) {
223 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
224 0 : return SQL_ERROR;
225 : }
226 8284 : stmt->params = temp_params;
227 :
228 33136 : switch (odbc_sql2tds
229 8284 : (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
230 24852 : stmt->params->columns[nparam], compute_row, stmt->apd, stmt->curr_param_row)) {
231 : case SQL_ERROR:
232 : return SQL_ERROR;
233 332 : case SQL_NEED_DATA:
234 332 : return SQL_NEED_DATA;
235 : }
236 : }
237 : return SQL_SUCCESS;
238 : }
239 :
240 : int
241 33581 : start_parse_prepared_query(struct _hstmt *stmt, bool compute_row)
242 : {
243 : /* TODO should be NULL already ?? */
244 33581 : tds_free_param_results(stmt->params);
245 33581 : stmt->params = NULL;
246 :
247 33581 : stmt->param_num = stmt->prepared_query_is_func ? 2 : 1;
248 33581 : return parse_prepared_query(stmt, compute_row);
249 : }
250 :
251 : static ptrdiff_t
252 60 : odbc_wchar2hex(TDS_CHAR *dest, size_t destlen, const SQLWCHAR * src, size_t srclen)
253 : {
254 : size_t i;
255 60 : SQLWCHAR hex1, c = 0;
256 :
257 : /* if srclen if odd we must add a "0" before ... */
258 60 : i = 0; /* number where to start converting */
259 60 : if (srclen & 1) {
260 0 : ++srclen;
261 0 : i = 1;
262 0 : --src;
263 : }
264 400020 : for (; i < srclen; ++i) {
265 400020 : hex1 = src[i];
266 :
267 400020 : if ('0' <= hex1 && hex1 <= '9')
268 346160 : hex1 &= 0x0f;
269 : else {
270 53860 : hex1 |= 0x20; /* ensure lower case */
271 53860 : if ('a' <= hex1 && hex1 <= 'f') {
272 53860 : hex1 -= ('a' - 10);
273 : } else {
274 0 : tdsdump_log(TDS_DBG_INFO1,
275 : "error_handler: attempt to convert data stopped by syntax error in source field \n");
276 : return TDS_CONVERT_SYNTAX;
277 : }
278 : }
279 400020 : tds_extra_assert(hex1 < 0x10);
280 :
281 400020 : if ((i/2u) >= destlen)
282 0 : continue;
283 :
284 400020 : if (i & 1)
285 200010 : dest[i / 2u] = c | hex1;
286 : else
287 200010 : c = hex1 << 4;
288 : }
289 60 : return srclen / 2u;
290 : }
291 :
292 :
293 : int
294 832 : continue_parse_prepared_query(struct _hstmt *stmt, SQLPOINTER DataPtr, SQLLEN StrLen_or_Ind)
295 : {
296 : struct _drecord *drec_apd, *drec_ipd;
297 : SQLLEN len;
298 : int need_bytes;
299 : TDSCOLUMN *curcol;
300 : TDSBLOB *blob;
301 : int sql_src_type;
302 :
303 832 : assert(stmt);
304 :
305 832 : tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);
306 :
307 832 : if (!stmt->params) {
308 0 : tdsdump_log(TDS_DBG_FUNC, "error? continue_parse_prepared_query: no parameters provided");
309 : return SQL_ERROR;
310 : }
311 :
312 832 : if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
313 : return SQL_ERROR;
314 832 : drec_apd = &stmt->apd->records[stmt->param_num - 1];
315 832 : drec_ipd = &stmt->ipd->records[stmt->param_num - 1];
316 :
317 832 : curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
318 832 : blob = NULL;
319 832 : if (is_blob_col(curcol))
320 832 : blob = (TDSBLOB *) curcol->column_data;
321 832 : assert(curcol->column_cur_size <= curcol->column_size);
322 832 : need_bytes = curcol->column_size - curcol->column_cur_size;
323 :
324 832 : if (DataPtr == NULL) {
325 0 : switch(StrLen_or_Ind) {
326 : case SQL_NULL_DATA:
327 : case SQL_DEFAULT_PARAM:
328 : break; /* OK */
329 0 : default:
330 0 : odbc_errs_add(&stmt->errs, "HY009", NULL); /* Invalid use of null pointer */
331 0 : return SQL_ERROR;
332 : }
333 832 : }
334 :
335 : /* get C type */
336 832 : sql_src_type = drec_apd->sql_desc_concise_type;
337 832 : if (sql_src_type == SQL_C_DEFAULT)
338 0 : sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);
339 :
340 832 : switch(StrLen_or_Ind) {
341 0 : case SQL_NTS:
342 0 : if (sql_src_type == SQL_C_WCHAR)
343 0 : len = sqlwcslen((SQLWCHAR *) DataPtr);
344 : else
345 0 : len = strlen((char *) DataPtr);
346 : break;
347 : case SQL_NULL_DATA:
348 : len = 0;
349 : break;
350 0 : case SQL_DEFAULT_PARAM:
351 : /* FIXME: use the default if the parameter has one. */
352 0 : odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */
353 0 : return SQL_ERROR;
354 832 : default:
355 832 : if (DataPtr && StrLen_or_Ind < 0) {
356 : /*
357 : * "The argument DataPtr was not a null pointer, and
358 : * the argument StrLen_or_Ind was less than 0
359 : * but not equal to SQL_NTS or SQL_NULL_DATA."
360 : */
361 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
362 0 : return SQL_ERROR;
363 : }
364 : len = StrLen_or_Ind;
365 : break;
366 : }
367 :
368 832 : if (!blob && len > need_bytes)
369 0 : len = need_bytes;
370 :
371 : /* copy to destination */
372 832 : if (blob) {
373 : TDS_CHAR *p;
374 832 : int binary_convert = 0;
375 832 : SQLLEN orig_len = len;
376 :
377 832 : if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
378 656 : TDS_SERVER_TYPE type = tds_get_conversion_type(curcol->column_type, curcol->column_size);
379 656 : if (is_binary_type(type)) {
380 80 : if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
381 0 : --len;
382 :
383 80 : if (sql_src_type == SQL_C_WCHAR)
384 40 : len /= sizeof(SQLWCHAR);
385 :
386 80 : if (!len)
387 : return SQL_SUCCESS;
388 :
389 80 : binary_convert = 1;
390 80 : orig_len = len;
391 80 : len = len / 2u + 1u;
392 : }
393 : }
394 :
395 832 : if (!len)
396 : return SQL_SUCCESS;
397 :
398 800 : assert(blob->textvalue || curcol->column_cur_size == 0);
399 800 : p = (TDS_CHAR *) TDS_RESIZE(blob->textvalue, len + curcol->column_cur_size);
400 800 : if (!p) {
401 0 : odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
402 0 : return SQL_ERROR;
403 : }
404 :
405 800 : p += curcol->column_cur_size;
406 800 : if (binary_convert) {
407 : ptrdiff_t res;
408 :
409 80 : len = orig_len;
410 :
411 80 : if (curcol->column_cur_size > 0
412 40 : && curcol->column_text_sqlputdatainfo) {
413 : SQLWCHAR data[2];
414 20 : data[0] = curcol->column_text_sqlputdatainfo;
415 20 : data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;
416 :
417 20 : res = odbc_wchar2hex(p, 1, data, 2);
418 20 : if (res < 0) {
419 0 : odbc_convert_err_set(&stmt->errs, (TDS_INT) res);
420 0 : return SQL_ERROR;
421 : }
422 20 : p += res;
423 :
424 20 : DataPtr = (SQLPOINTER) (((char*)DataPtr) +
425 20 : (sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
426 20 : --len;
427 : }
428 :
429 80 : if (len&1) {
430 20 : --len;
431 40 : curcol->column_text_sqlputdatainfo =
432 20 : (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
433 : }
434 :
435 80 : res = (sql_src_type == SQL_C_CHAR) ?
436 120 : tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
437 40 : odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
438 80 : if (res < 0) {
439 0 : odbc_convert_err_set(&stmt->errs, (TDS_INT) res);
440 0 : return SQL_ERROR;
441 : }
442 80 : p += res;
443 :
444 80 : len = p - (blob->textvalue + curcol->column_cur_size);
445 : } else {
446 720 : memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
447 : }
448 0 : } else if (len > 0) {
449 0 : memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
450 : }
451 :
452 800 : curcol->column_cur_size += len;
453 :
454 800 : if (blob && curcol->column_cur_size > curcol->column_size)
455 520 : curcol->column_size = curcol->column_cur_size;
456 :
457 : return SQL_SUCCESS;
458 : }
|