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