NCBI C++ ToolKit
prepare_query.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, 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 
40 #define TDS_ISSPACE(c) isspace((unsigned char) (c))
41 
42 static int
43 prepared_rpc(struct _hstmt *stmt, int compute_row)
44 {
45  int nparam = stmt->params ? stmt->params->num_cols : 0;
46  const char *p = stmt->prepared_pos - 1;
47  TDSCONNECTION *conn = stmt->dbc->tds_socket->conn;
48 
49  for (;;) {
50  TDSPARAMINFO *temp_params;
51  TDSCOLUMN *curcol;
53  const char *start;
54 
55  while (TDS_ISSPACE(*++p))
56  continue;
57  if (!*p)
58  return SQL_SUCCESS;
59 
60  /* we have certainly a parameter */
61  if (!(temp_params = tds_alloc_param_result(stmt->params))) {
62  odbc_errs_add(&stmt->errs, "HY001", NULL);
63  return SQL_ERROR;
64  }
65  stmt->params = temp_params;
66  curcol = temp_params->columns[nparam];
67 
68  switch (*p) {
69  case ',':
70  if (IS_TDS7_PLUS(conn)) {
72  curcol->column_size = curcol->column_cur_size = 0;
73  } else {
74  /* TODO is there a better type ? */
76  curcol->column_size = curcol->on_server.column_size = 4;
77  curcol->column_cur_size = -1;
78  }
79  if (compute_row)
80  if (!tds_alloc_param_data(curcol)) {
81  tds_free_param_result(temp_params);
82  return SQL_ERROR;
83  }
84  --p;
85  break;
86  default:
87  /* add next parameter to list */
88  start = p;
89 
90  if (!(p = parse_const_param(p, &type))) {
91  tds_free_param_result(temp_params);
92  return SQL_ERROR;
93  }
94  tds_set_param_type(conn, curcol, type);
95  switch (type) {
96  case SYBVARCHAR:
97  curcol->column_size = p - start;
98  break;
99  case SYBVARBINARY:
100  curcol->column_size = (p - start) / 2 -1;
101  break;
102  default:
103  assert(0);
104  case SYBINT4:
105  case SYBFLT8:
106  curcol->column_cur_size = curcol->column_size;
107  break;
108  }
109  curcol->on_server.column_size = curcol->column_size;
110  /* TODO support other type other than VARCHAR, do not strip escape in prepare_call */
111  if (compute_row) {
112  char *dest;
113  int len;
114  CONV_RESULT cr;
115 
116  if (!tds_alloc_param_data(curcol)) {
117  tds_free_param_result(temp_params);
118  return SQL_ERROR;
119  }
120  dest = (char *) curcol->column_data;
121  switch (type) {
122  case SYBVARCHAR:
123  if (*start != '\'') {
124  memcpy(dest, start, p - start);
125  curcol->column_cur_size = p - start;
126  } else {
127  ++start;
128  for (;;) {
129  if (*start == '\'')
130  ++start;
131  if (start >= p)
132  break;
133  *dest++ = *start++;
134  }
135  curcol->column_cur_size =
136  dest - (char *) curcol->column_data;
137  }
138  break;
139  case SYBVARBINARY:
140  cr.cb.len = curcol->column_size;
141  cr.cb.ib = dest;
142  len = tds_convert(NULL, SYBVARCHAR, start, p - start, TDS_CONVERT_BINARY, &cr);
143  if (len >= 0 && len <= curcol->column_size)
144  curcol->column_cur_size = len;
145  break;
146  case SYBINT4:
147  *((TDS_INT *) dest) = atoi(start);
148  break;
149  case SYBFLT8:
150  *((TDS_FLOAT *) dest) = strtod(start, NULL);
151  break;
152  default:
153  break;
154  }
155  }
156  --p;
157  break;
158  case '?':
159  /* find bound parameter */
160  if (stmt->param_num > stmt->apd->header.sql_desc_count
161  || stmt->param_num > stmt->ipd->header.sql_desc_count) {
162  tds_free_param_result(temp_params);
163  /* TODO set error */
164  return SQL_ERROR;
165  }
166 
167  switch (odbc_sql2tds
168  (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
169  curcol, compute_row, stmt->apd, stmt->curr_param_row)) {
170  case SQL_ERROR:
171  return SQL_ERROR;
172  case SQL_NEED_DATA:
173  return SQL_NEED_DATA;
174  }
175  ++stmt->param_num;
176  break;
177  }
178  ++nparam;
179 
180  while (TDS_ISSPACE(*++p))
181  continue;
182  if (!*p || *p != ',')
183  return SQL_SUCCESS;
184  stmt->prepared_pos = (char *) p + 1;
185  }
186 }
187 
188 int
189 parse_prepared_query(struct _hstmt *stmt, int compute_row)
190 {
191  /* try setting this parameter */
192  TDSPARAMINFO *temp_params;
193  int nparam = stmt->params ? stmt->params->num_cols : 0;
194 
195  if (stmt->prepared_pos)
196  return prepared_rpc(stmt, compute_row);
197 
198  tdsdump_log(TDS_DBG_FUNC, "parsing %d parameters\n", nparam);
199 
200  for (; stmt->param_num <= (int) stmt->param_count;
201  ++nparam, ++stmt->param_num) {
202  /* find bound parameter */
203  if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count) {
204  tdsdump_log(TDS_DBG_FUNC, "parse_prepared_query: logic_error: parameter out of bounds: "
205  "%d > %d || %d > %d\n",
206  stmt->param_num, stmt->apd->header.sql_desc_count,
207  stmt->param_num, stmt->ipd->header.sql_desc_count);
208  return SQL_ERROR;
209  }
210 
211  /* add a column to parameters */
212  if (!(temp_params = tds_alloc_param_result(stmt->params))) {
213  odbc_errs_add(&stmt->errs, "HY001", NULL);
214  return SQL_ERROR;
215  }
216  stmt->params = temp_params;
217 
218  switch (odbc_sql2tds
219  (stmt, &stmt->ipd->records[stmt->param_num - 1], &stmt->apd->records[stmt->param_num - 1],
220  stmt->params->columns[nparam], compute_row, stmt->apd, stmt->curr_param_row)) {
221  case SQL_ERROR:
222  return SQL_ERROR;
223  case SQL_NEED_DATA:
224  return SQL_NEED_DATA;
225  }
226  }
227  return SQL_SUCCESS;
228 }
229 
230 int
231 start_parse_prepared_query(struct _hstmt *stmt, int compute_row)
232 {
233  /* TODO should be NULL already ?? */
234  tds_free_param_results(stmt->params);
235  stmt->params = NULL;
236  stmt->param_num = 0;
237 
238  stmt->param_num = stmt->prepared_query_is_func ? 2 : 1;
239  return parse_prepared_query(stmt, compute_row);
240 }
241 
242 static ssize_t
243 odbc_wchar2hex(TDS_CHAR *dest, size_t destlen, const SQLWCHAR * src,
244  size_t srclen)
245 {
246  size_t i;
247  SQLWCHAR hex1, c = 0;
248 
249  /* if srclen if odd we must add a "0" before ... */
250  i = 0; /* number where to start converting */
251  if (srclen & 1) {
252  ++srclen;
253  i = 1;
254  --src;
255  }
256  for (; i < srclen; ++i) {
257  hex1 = src[i];
258 
259  if ('0' <= hex1 && hex1 <= '9')
260  hex1 &= 0x0f;
261  else {
262  hex1 &= (SQLWCHAR) ~0x20u; /* mask off 0x20 to ensure upper case */
263  if ('A' <= hex1 && hex1 <= 'F') {
264  hex1 -= ('A' - 10);
265  } else {
267  "error_handler: attempt to convert data stopped by syntax error in source field \n");
268  return TDS_CONVERT_SYNTAX;
269  }
270  }
271  assert(hex1 < 0x10);
272 
273  if ((i/2u) >= destlen)
274  continue;
275 
276  if (i & 1)
277  dest[i / 2u] = c | hex1;
278  else
279  c = hex1 << 4;
280  }
281  return srclen / 2u;
282 }
283 
284 
285 int
287 {
288  struct _drecord *drec_apd, *drec_ipd;
289  SQLLEN len;
290  int need_bytes;
291  TDSCOLUMN *curcol;
292  TDSBLOB *blob;
293  int sql_src_type;
294 
295  assert(stmt);
296 
297  tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);
298 
299  if (!stmt->params) {
300  tdsdump_log(TDS_DBG_FUNC, "error? continue_parse_prepared_query: no parameters provided");
301  return SQL_ERROR;
302  }
303 
304  if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
305  return SQL_ERROR;
306  drec_apd = &stmt->apd->records[stmt->param_num - 1];
307  drec_ipd = &stmt->ipd->records[stmt->param_num - 1];
308 
309  curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
310  blob = NULL;
311  if (is_blob_col(curcol))
312  blob = (TDSBLOB *) curcol->column_data;
313  assert(curcol->column_cur_size <= curcol->column_size);
314  need_bytes = curcol->column_size - curcol->column_cur_size;
315 
316  if (DataPtr == NULL) {
317  switch(StrLen_or_Ind) {
318  case SQL_NULL_DATA:
319  case SQL_DEFAULT_PARAM:
320  break; /* OK */
321  default:
322  odbc_errs_add(&stmt->errs, "HY009", NULL); /* Invalid use of null pointer */
323  return SQL_ERROR;
324  }
325  }
326 
327  /* get C type */
328  sql_src_type = drec_apd->sql_desc_concise_type;
329  if (sql_src_type == SQL_C_DEFAULT)
330  sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);
331 
332  switch(StrLen_or_Ind) {
333  case SQL_NTS:
334  if (sql_src_type == SQL_C_WCHAR)
335  len = sqlwcslen((SQLWCHAR *) DataPtr);
336  else
337  len = strlen((char *) DataPtr);
338  break;
339  case SQL_NULL_DATA:
340  len = 0;
341  break;
342  case SQL_DEFAULT_PARAM:
343  /* FIXME: use the default if the parameter has one. */
344  odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */
345  return SQL_ERROR;
346  default:
347  if (DataPtr && StrLen_or_Ind < 0) {
348  /*
349  * "The argument DataPtr was not a null pointer, and
350  * the argument StrLen_or_Ind was less than 0
351  * but not equal to SQL_NTS or SQL_NULL_DATA."
352  */
353  odbc_errs_add(&stmt->errs, "HY090", NULL);
354  return SQL_ERROR;
355  }
356  len = StrLen_or_Ind;
357  break;
358  }
359 
360  if (!blob && len > need_bytes)
361  len = need_bytes;
362 
363  /* copy to destination */
364  if (blob) {
365  TDS_CHAR *p;
366  int binary_convert = 0;
367  SQLLEN orig_len = len;
368 
369  if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
370  switch (tds_get_conversion_type(curcol->column_type, curcol->column_size)) {
371  case SYBBINARY:
372  case SYBVARBINARY:
373  case XSYBBINARY:
374  case XSYBVARBINARY:
375  case SYBLONGBINARY:
376  case SYBIMAGE:
377  if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
378  --len;
379 
380  if (sql_src_type == SQL_C_WCHAR)
381  len /= sizeof(SQLWCHAR);
382 
383  if (!len)
384  return SQL_SUCCESS;
385 
386  binary_convert = 1;
387  orig_len = len;
388  len = len / 2u + 1u;
389  break;
390  default:
391  break;
392  }
393  }
394 
395  if (!len)
396  return SQL_SUCCESS;
397 
398  assert(blob->textvalue || curcol->column_cur_size == 0);
399  p = (TDS_CHAR *) TDS_RESIZE(blob->textvalue, len + curcol->column_cur_size);
400  if (!p) {
401  odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
402  return SQL_ERROR;
403  }
404 
405  p += curcol->column_cur_size;
406  if (binary_convert) {
407  ssize_t res;
408 
409  len = orig_len;
410 
411  if (curcol->column_cur_size > 0
412  && curcol->column_text_sqlputdatainfo) {
413  SQLWCHAR data[2];
414  data[0] = curcol->column_text_sqlputdatainfo;
415  data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;
416 
417  res = odbc_wchar2hex(p, 1, data, 2);
418  if (res < 0) {
419  odbc_convert_err_set(&stmt->errs,
420  (TDS_INT) res);
421  return SQL_ERROR;
422  }
423  p += res;
424 
425  DataPtr = (SQLPOINTER) (((char*)DataPtr) +
426  (sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
427  --len;
428  }
429 
430  if (len&1) {
431  --len;
432  curcol->column_text_sqlputdatainfo = (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
433  }
434 
435  res = (sql_src_type == SQL_C_CHAR) ?
436  tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
437  odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
438  if (res < 0) {
439  odbc_convert_err_set(&stmt->errs,
440  (TDS_INT) res);
441  return SQL_ERROR;
442  }
443  p += res;
444 
445  len = p - (blob->textvalue + curcol->column_cur_size);
446  } else {
447  memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
448  }
449  } else if (len > 0) {
450  memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
451  }
452 
453  curcol->column_cur_size += len;
454 
455  if (blob && curcol->column_cur_size > curcol->column_size)
456  curcol->column_size = curcol->column_cur_size;
457 
458  return SQL_SUCCESS;
459 }
#define TDS_CONVERT_SYNTAX
Definition: convert.h:78
#define TDS_CONVERT_BINARY
Definition: convert.h:84
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static int type
Definition: getdata.c:31
#define NULL
Definition: ncbistd.hpp:225
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int odbc_sql_to_c_type_default(int sql_type)
Definition: odbc_util.c:679
void odbc_convert_err_set(struct _sql_errors *errs, TDS_INT err)
Definition: odbc_util.c:1175
int i
int len
int ssize_t
Definition: ncbiconf_msvc.h:92
switch(yytype)
Definition: newick.tab.cpp:737
void odbc_errs_add(struct _sql_errors *errs, const char *sqlstate, const char *msg)
add an error to list
Definition: error.c:382
#define sqlwcslen(s)
Definition: odbc.h:719
const char * parse_const_param(const char *s, TDS_SERVER_TYPE *type)
Definition: native.c:183
#define SQLLEN
Definition: odbc.h:52
SQLRETURN odbc_sql2tds(TDS_STMT *stmt, const struct _drecord *drec_ixd, const struct _drecord *drec_axd, TDSCOLUMN *curcol, int compute_row, const TDS_DESC *axd, SQLUSMALLINT n_row)
int continue_parse_prepared_query(struct _hstmt *stmt, SQLPOINTER DataPtr, SQLLEN StrLen_or_Ind)
static ssize_t odbc_wchar2hex(TDS_CHAR *dest, size_t destlen, const SQLWCHAR *src, size_t srclen)
int parse_prepared_query(struct _hstmt *stmt, int compute_row)
static int prepared_rpc(struct _hstmt *stmt, int compute_row)
Definition: prepare_query.c:43
#define TDS_ISSPACE(c)
Definition: prepare_query.c:40
int start_parse_prepared_query(struct _hstmt *stmt, int compute_row)
TDS_SERVER_TYPE
Definition: proto.h:161
@ SYBLONGBINARY
Definition: proto.h:211
@ XSYBVARBINARY
Definition: proto.h:197
@ XSYBBINARY
Definition: proto.h:198
static HSTMT stmt
Definition: rebindpar.c:12
#define tds_set_param_type
#define tds_free_param_results
#define tds_char2hex
#define tds_alloc_param_result
#define tds_alloc_param_data
#define tds_get_conversion_type
#define tds_free_param_result
#define tds_convert
#define SQL_SUCCESS
Definition: sql.h:31
#define SQL_NEED_DATA
Definition: sql.h:39
#define SQL_NTS
Definition: sql.h:49
#define SQL_NULL_DATA
Definition: sql.h:29
#define SQL_ERROR
Definition: sql.h:36
#define SQL_C_DEFAULT
Definition: sqlext.h:519
#define SQL_DEFAULT_PARAM
Definition: sqlext.h:612
#define SQL_C_CHAR
Definition: sqlext.h:511
void * SQLPOINTER
Definition: sqltypes.h:195
WCHAR SQLWCHAR
Definition: sqltypes.h:458
#define SQL_C_WCHAR
Definition: sqlucode.h:17
#define assert(x)
Definition: srv_diag.hpp:58
Definition: odbc.h:164
SQLSMALLINT sql_desc_concise_type
Definition: odbc.h:170
Definition: odbc.h:390
TDS_UINT len
Definition: convert.h:68
TDS_CHAR * ib
Definition: convert.h:67
Information about blobs (e.g.
Definition: tds.h:658
TDS_CHAR * textvalue
Definition: tds.h:659
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
unsigned char * column_data
Definition: tds.h:793
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
TDS_CHAR column_text_sqlputdatainfo
Definition: tds.h:823
struct tds_column::@124 on_server
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
Hold information for any results.
Definition: tds.h:842
TDSCOLUMN ** columns
Definition: tds.h:844
Definition: type.c:6
#define SYBVOID
Definition: sybdb.h:198
#define SYBINT4
Definition: sybdb.h:170
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBIMAGE
Definition: sybdb.h:186
#define SYBINTN
Definition: sybdb.h:164
#define SYBBINARY
Definition: sybdb.h:196
#define SYBVARBINARY
Definition: sybdb.h:200
#define SYBFLT8
Definition: sybdb.h:174
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
tds_sysdep_real64_type TDS_FLOAT
Definition: tds.h:152
#define is_blob_col(x)
Definition: tds.h:445
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
char TDS_CHAR
Definition: tds.h:144
#define TDS_RESIZE(p, n_elem)
Definition: tds.h:1390
#define TDS_DBG_FUNC
Definition: tds.h:898
struct conv_result::cb_t cb
Modified on Wed Dec 06 07:13:07 2023 by modify_doxy.py rev. 669887