Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3 : * Copyright (C) 2010, 2011 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_STRING_H
28 : #include <string.h>
29 : #endif /* HAVE_STRING_H */
30 :
31 : #if HAVE_STDLIB_H
32 : #include <stdlib.h>
33 : #endif /* HAVE_STDLIB_H */
34 :
35 : #if HAVE_UNISTD_H
36 : #include <unistd.h>
37 : #endif /* HAVE_UNISTD_H */
38 :
39 : #ifdef _WIN32
40 : #include <io.h>
41 : #endif
42 :
43 : #include <freetds/tds.h>
44 : #include <freetds/tds/iconv.h>
45 : #include <freetds/tds/convert.h>
46 : #include <freetds/odbc.h>
47 : #include <freetds/utils/string.h>
48 : #define TDSODBC_BCP
49 : #include <odbcss.h>
50 :
51 : static TDSRET _bcp_get_col_data(TDSBCPINFO * bcpinfo, TDSCOLUMN * bindcol, int index, int offset);
52 : static SQLLEN
53 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len);
54 :
55 : #define ODBCBCP_ERROR_RETURN(code) \
56 : do {odbc_errs_add(&dbc->errs, code, NULL); return;} while(0)
57 :
58 : #define ODBCBCP_ERROR_DBINT(code) \
59 : do {odbc_errs_add(&dbc->errs, code, NULL); return -1;} while(0)
60 :
61 : /**
62 : * \ingroup odbc_bcp
63 : * \brief Prepare for bulk copy operation on a table
64 : *
65 : * \param dbc ODBC database connection object
66 : * \param tblname the name of the table receiving or providing the data.
67 : * \param hfile the data file opposite the table, if any. NB: The current
68 : * implementation does not support file I/O so this must be NULL
69 : * \param errfile the "error file" captures messages and, if errors are
70 : * encountered. NB: The current implementation does not support
71 : * file I/O so this must be NULL
72 : * \param direction one of
73 : * - \b DB_IN writing to the table
74 : * - \b DB_OUT writing to the host file (Not currently supported)
75 : * .
76 : * \remarks bcp_init() sets the host file data format and acquires the table metadata.
77 : * It is called before the other bulk copy functions.
78 : *
79 : * The ODBC BCP functionality should be accessed via the inline functions in
80 : * odbcss.h.
81 : *
82 : * After calling this function, call bcp_bind() to associate your data with
83 : * the appropriate table column.
84 : *
85 : * \sa SQL_COPT_SS_BCP, odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_exec()
86 : */
87 : void
88 34 : odbc_bcp_init(TDS_DBC *dbc, const ODBC_CHAR *tblname, const ODBC_CHAR *hfile,
89 : const ODBC_CHAR *errfile, int direction _WIDE)
90 : {
91 34 : if (TDS_UNLIKELY(tds_write_dump)) {
92 : #ifdef ENABLE_ODBC_WIDE
93 0 : if (wide) {
94 0 : SQLWSTR_BUFS(3);
95 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_initW(%p, %ls, %ls, %ls, %d)\n",
96 : dbc, SQLWSTR(tblname->wide), SQLWSTR(hfile->wide), SQLWSTR(errfile->wide), direction);
97 0 : SQLWSTR_FREE();
98 : } else {
99 : #else
100 : {
101 : #endif
102 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n",
103 : dbc, (const char*) tblname, (const char*) hfile, (const char*) errfile, direction);
104 : }
105 : }
106 34 : if (!tblname)
107 0 : ODBCBCP_ERROR_RETURN("HY009");
108 :
109 : /* Free previously allocated storage in dbproc & initialise flags, etc. */
110 :
111 34 : odbc_bcp_free_storage(dbc);
112 :
113 : /*
114 : * Validate other parameters
115 : */
116 34 : if (dbc->tds_socket->conn->tds_version < 0x500)
117 0 : ODBCBCP_ERROR_RETURN("HYC00");
118 :
119 34 : if (direction != BCP_DIRECTION_IN || hfile || errfile)
120 0 : ODBCBCP_ERROR_RETURN("HYC00");
121 :
122 : /* Allocate storage */
123 :
124 34 : dbc->bcpinfo = tds_alloc_bcpinfo();
125 34 : if (dbc->bcpinfo == NULL)
126 0 : ODBCBCP_ERROR_RETURN("HY001");
127 :
128 34 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->tablename, SQL_NTS, tblname)) {
129 0 : odbc_bcp_free_storage(dbc);
130 0 : ODBCBCP_ERROR_RETURN("HY001");
131 : }
132 :
133 68 : if (tds_dstr_len(&dbc->bcpinfo->tablename) > 92 && !IS_TDS7_PLUS(dbc->tds_socket->conn)) { /* 30.30.30 */
134 0 : odbc_bcp_free_storage(dbc);
135 0 : ODBCBCP_ERROR_RETURN("HYC00");
136 : }
137 :
138 34 : dbc->bcpinfo->direction = direction;
139 :
140 34 : dbc->bcpinfo->xfer_init = false;
141 34 : dbc->bcpinfo->bind_count = 0;
142 :
143 34 : if (TDS_FAILED(tds_bcp_init(dbc->tds_socket, dbc->bcpinfo))) {
144 : /* TODO return proper error */
145 : /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
146 0 : ODBCBCP_ERROR_RETURN("HY000");
147 : }
148 : }
149 :
150 :
151 : /**
152 : * \ingroup odbc_bcp
153 : * \brief Set BCP options for data transfer
154 : *
155 : * \param dbc ODBC database connection object
156 : * \param field symbolic constant indicating the option to be set, one of:
157 : * - \b BCPKEEPIDENTITY Enable identity insert, as if by executing
158 : * 'SET IDENTITY_INSERT \a table ON'. The default is off
159 : * - \b BCPHINTS Arbitrary extra text to pass to the server. See the
160 : * documentation for the bcp command-line tool which came with your
161 : * database server for the correct syntax.
162 : * \param value The value for \a field.
163 : *
164 : * \remarks These options control the behavior of bcp_sendrow().
165 : *
166 : * \sa odbc_bcp_batch(), odbc_bcp_init(), odbc_bcp_done()
167 : */
168 : void
169 4 : odbc_bcp_control(TDS_DBC *dbc, int field, void *value)
170 : {
171 : #ifdef ENABLE_ODBC_WIDE
172 4 : int wide = 0;
173 : #endif
174 :
175 4 : tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %p)\n", dbc, field, value);
176 4 : if (dbc->bcpinfo == NULL)
177 0 : ODBCBCP_ERROR_RETURN("HY010");
178 :
179 :
180 4 : switch (field) {
181 0 : case BCPKEEPIDENTITY:
182 0 : dbc->bcpinfo->identity_insert_on = (value != NULL);
183 0 : break;
184 4 : case BCPHINTSA:
185 4 : if (!value)
186 0 : ODBCBCP_ERROR_RETURN("HY009");
187 4 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->hint, SQL_NTS, (ODBC_CHAR *) value))
188 0 : ODBCBCP_ERROR_RETURN("HY001");
189 : break;
190 : #ifdef ENABLE_ODBC_WIDE
191 0 : case BCPHINTSW:
192 0 : if (!value)
193 0 : ODBCBCP_ERROR_RETURN("HY009");
194 0 : wide = 1;
195 0 : if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->hint, SQL_NTS, (ODBC_CHAR *) value))
196 0 : ODBCBCP_ERROR_RETURN("HY001");
197 : break;
198 : #endif
199 0 : default:
200 0 : ODBCBCP_ERROR_RETURN("HY009");
201 : }
202 : }
203 :
204 : /**
205 : * \ingroup odbc_bcp
206 : * \brief Override bcp_bind() by pointing to a different host variable.
207 : *
208 : * \param dbc ODBC database connection object
209 : * \param colptr The pointer, the address of your variable.
210 : * \param table_column The 1-based column ordinal in the table.
211 : * \remarks Use between calls to bcp_sendrow(). After calling bcp_colptr(),
212 : * subsequent calls to bcp_sendrow() will bind to the new address.
213 : * \sa odbc_bcp_bind(), odbc_bcp_sendrow()
214 : */
215 : void
216 0 : odbc_bcp_colptr(TDS_DBC *dbc, const void * colptr, int table_column)
217 : {
218 : TDSCOLUMN *curcol;
219 :
220 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbc, colptr, table_column);
221 0 : if (dbc->bcpinfo == NULL || dbc->bcpinfo->bindinfo == NULL)
222 0 : ODBCBCP_ERROR_RETURN("HY010");
223 : /* colptr can be NULL */
224 :
225 0 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
226 0 : ODBCBCP_ERROR_RETURN("HY010");
227 0 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
228 0 : ODBCBCP_ERROR_RETURN("HY009");
229 :
230 0 : curcol = dbc->bcpinfo->bindinfo->columns[table_column - 1];
231 0 : curcol->column_varaddr = (TDS_CHAR *)colptr;
232 : }
233 :
234 :
235 : /**
236 : * \ingroup odbc_bcp
237 : * \brief Write data in host variables to the table.
238 : *
239 : * \param dbc ODBC database connection object
240 : *
241 : * \remarks Call bcp_bind() first to describe the variables to be used.
242 : * Use bcp_batch() to commit sets of rows.
243 : * After sending the last row call bcp_done().
244 : * \sa odbc_bcp_batch(), odbc_bcp_bind(), odbc_bcp_colptr(), odbc_bcp_done(),
245 : * odbc_bcp_init()
246 : */
247 : void
248 204 : odbc_bcp_sendrow(TDS_DBC *dbc)
249 : {
250 : TDSSOCKET *tds;
251 :
252 204 : tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc);
253 204 : if (dbc->bcpinfo == NULL)
254 0 : ODBCBCP_ERROR_RETURN("HY010");
255 :
256 204 : tds = dbc->tds_socket;
257 :
258 204 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
259 0 : ODBCBCP_ERROR_RETURN("HY010");
260 :
261 : /*
262 : * The first time sendrow is called after bcp_init,
263 : * there is a certain amount of initialisation to be done.
264 : */
265 204 : if (!dbc->bcpinfo->xfer_init) {
266 :
267 : /* The start_copy function retrieves details of the table's columns */
268 24 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo)))
269 0 : ODBCBCP_ERROR_RETURN("HY000");
270 :
271 24 : dbc->bcpinfo->xfer_init = true;
272 : }
273 :
274 204 : dbc->bcpinfo->parent = dbc;
275 204 : if (TDS_FAILED(tds_bcp_send_record(dbc->tds_socket, dbc->bcpinfo, _bcp_get_col_data, NULL, 0)))
276 0 : ODBCBCP_ERROR_RETURN("HY000");
277 : }
278 :
279 :
280 : /**
281 : * \ingroup odbc_bcp
282 : * \brief Commit a set of rows to the table.
283 : *
284 : * \param dbc ODBC database connection object
285 : * \remarks If not called, bcp_done() will cause the rows to be saved.
286 : * \return Count of rows saved, or -1 on error.
287 : * \sa odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_sendrow()
288 : */
289 : int
290 24 : odbc_bcp_batch(TDS_DBC *dbc)
291 : {
292 24 : int rows_copied = 0;
293 :
294 24 : tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc);
295 24 : if (dbc->bcpinfo == NULL)
296 0 : ODBCBCP_ERROR_DBINT("HY010");
297 :
298 24 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
299 0 : ODBCBCP_ERROR_DBINT("HY000");
300 :
301 24 : tds_bcp_start(dbc->tds_socket, dbc->bcpinfo);
302 :
303 24 : return rows_copied;
304 : }
305 :
306 : /**
307 : * \ingroup odbc_bcp
308 : * \brief Conclude the transfer of data from program variables.
309 : *
310 : * \param dbc ODBC database connection object
311 : * \remarks Do not overlook this function. According to Sybase, failure to call bcp_done()
312 : * "will result in unpredictable errors".
313 : * \return As with bcp_batch(), the count of rows saved, or -1 on error.
314 : * \sa bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
315 : */
316 : int
317 34 : odbc_bcp_done(TDS_DBC *dbc)
318 : {
319 : int rows_copied;
320 :
321 34 : tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
322 :
323 34 : if (!(dbc->bcpinfo))
324 0 : ODBCBCP_ERROR_DBINT("HY010");
325 :
326 34 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
327 10 : ODBCBCP_ERROR_DBINT("HY000");
328 :
329 24 : odbc_bcp_free_storage(dbc);
330 :
331 24 : return rows_copied;
332 : }
333 :
334 : /**
335 : * \ingroup odbc_bcp
336 : * \brief Bind a program host variable to a database column
337 : *
338 : * \param dbc ODBC database connection object
339 : * \param varaddr address of host variable
340 : * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
341 : * Use zero for fixed-length datatypes.
342 : * \param varlen bytes of data in \a varaddr. Zero for NULL, -1 for fixed-length datatypes.
343 : * \param terminator byte sequence that marks the end of the data in \a varaddr
344 : * \param termlen length of \a terminator
345 : * \param vartype datatype of the host variable
346 : * \param table_column Nth column, starting at 1, in the table.
347 : *
348 : * \remarks The order of operation is:
349 : * - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
350 : * - bcp_bind(), once per column you want to write to
351 : * - bcp_batch(), optionally, to commit a set of rows
352 : * - bcp_done()
353 : *
354 : * \sa odbc_bcp_batch(), odbc_bcp_done(), odbc_bcp_sendrow()
355 : */
356 : void
357 692 : odbc_bcp_bind(TDS_DBC *dbc, const void * varaddr, int prefixlen, int varlen,
358 : const void * terminator, int termlen, int vartype, int table_column)
359 : {
360 : TDSCOLUMN *colinfo;
361 : TDSICONV *conv;
362 :
363 692 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %d, %d)\n",
364 : dbc, varaddr, prefixlen, varlen,
365 : terminator, termlen, vartype, table_column);
366 692 : if (!dbc->bcpinfo)
367 0 : ODBCBCP_ERROR_RETURN("HY010");
368 :
369 692 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
370 0 : ODBCBCP_ERROR_RETURN("HY010");
371 :
372 692 : if (varlen < -1 && varlen != SQL_VARLEN_DATA)
373 0 : ODBCBCP_ERROR_RETURN("HY009");
374 :
375 692 : if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
376 0 : ODBCBCP_ERROR_RETURN("HY009");
377 :
378 1374 : if (vartype != 0 && !is_tds_type_valid(vartype))
379 0 : ODBCBCP_ERROR_RETURN("HY004");
380 :
381 : /* like MS, a NULL terminator is an error */
382 692 : if (termlen > 0 && terminator == NULL)
383 20 : ODBCBCP_ERROR_RETURN("HY009");
384 :
385 672 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
386 0 : ODBCBCP_ERROR_RETURN("HY009");
387 :
388 672 : if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
389 0 : ODBCBCP_ERROR_RETURN("HY009");
390 :
391 672 : colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1];
392 :
393 : /* without length, prefix or terminator there is no way to know the size of variable data */
394 672 : if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen <= 0) {
395 100 : TDS_SERVER_TYPE type = (TDS_SERVER_TYPE) vartype;
396 :
397 : /* type 0 means the program variable has the same type as the column */
398 100 : if (type == 0)
399 10 : type = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
400 100 : if (!is_fixed_type(type)) {
401 40 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", type);
402 40 : ODBCBCP_ERROR_RETURN("HY009");
403 : }
404 : }
405 :
406 : /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
407 : and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
408 632 : if (varaddr == NULL && varlen >= 0) {
409 0 : int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
410 0 : (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
411 : if( !fOK ) {
412 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
413 : colinfo->column_type, vartype);
414 0 : ODBCBCP_ERROR_RETURN("HY009");
415 : }
416 : }
417 :
418 632 : colinfo->column_varaddr = (char *)varaddr;
419 632 : colinfo->column_bindtype = vartype;
420 632 : colinfo->column_bindlen = varlen;
421 632 : colinfo->bcp_prefix_len = prefixlen;
422 :
423 632 : conv = colinfo->char_conv;
424 632 : if (conv) {
425 136 : TDSCONNECTION *conn = dbc->tds_socket->conn;
426 136 : TDS_SERVER_TYPE desttype = tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size);
427 136 : TDS_SERVER_TYPE srctype = colinfo->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) colinfo->column_bindtype;
428 136 : int src_charset = is_unicode_type(srctype) ? odbc_get_wide_canonic(conn) : dbc->original_charset_num;
429 :
430 136 : colinfo->char_conv = tds_iconv_get_info(conn, src_charset, conv->to.charset.canonic);
431 : }
432 :
433 632 : TDS_ZERO_FREE(colinfo->bcp_terminator);
434 632 : colinfo->bcp_term_len = 0;
435 632 : if (termlen > 0) {
436 0 : if ((colinfo->bcp_terminator = tds_new(TDS_CHAR, termlen)) == NULL)
437 0 : ODBCBCP_ERROR_RETURN("HY001");
438 0 : memcpy(colinfo->bcp_terminator, terminator, termlen);
439 0 : colinfo->bcp_term_len = termlen;
440 : }
441 : }
442 :
443 : static SQLLEN
444 616 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
445 : {
446 616 : if (bindcol->char_conv) {
447 616 : char *orig_dest = dest;
448 :
449 616 : if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
450 : return -1;
451 616 : return dest - orig_dest;
452 : }
453 :
454 0 : if (destlen > srclen)
455 0 : destlen = srclen;
456 0 : memcpy(dest, src, destlen);
457 0 : return destlen;
458 : }
459 :
460 : static TDS_INT
461 3028 : _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len,
462 : int desttype, unsigned char * dest, TDSCOLUMN *bindcol)
463 : {
464 : CONV_RESULT dres;
465 : TDS_INT ret;
466 : TDS_INT len;
467 3028 : TDS_INT destlen = bindcol->column_size;
468 : ODBC_CONVERT_BUF convert_buf;
469 3028 : bool always_convert = false;
470 :
471 3028 : assert(src_len >= 0);
472 3028 : assert(src != NULL);
473 3028 : assert(dest != NULL);
474 3028 : assert(destlen > 0);
475 :
476 3028 : tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n",
477 : dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen);
478 :
479 3028 : switch (srctype) {
480 4 : case SYBMSDATETIME2:
481 4 : convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &convert_buf.dta);
482 4 : convert_buf.dta.time_prec = (destlen - 40) / 2;
483 4 : src = (char *) &convert_buf.dta;
484 4 : break;
485 8 : case SYBDECIMAL:
486 : case SYBNUMERIC:
487 8 : if (convert_numeric2server(&dbc->errs, src, &convert_buf.num) <= 0)
488 : return -1;
489 8 : src = (char *) &convert_buf.num;
490 8 : always_convert = convert_buf.num.scale != bindcol->column_scale;
491 8 : break;
492 : /* TODO intervals */
493 : }
494 :
495 : /* oft times we are asked to convert a data type to itself */
496 3028 : if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
497 820 : if (is_char_type(desttype)) {
498 612 : ret = (TDS_INT) _bcp_iconv_helper (dbc, bindcol, src, src_len, (char *)dest, destlen);
499 : } else {
500 208 : ret = destlen < src_len ? destlen : (TDS_INT) src_len;
501 208 : memcpy(dest, src, ret);
502 : }
503 : return ret;
504 : }
505 :
506 2208 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
507 :
508 2208 : if (is_numeric_type(desttype)) {
509 404 : dres.n.precision = bindcol->column_prec;
510 404 : dres.n.scale = bindcol->column_scale;
511 : }
512 2208 : len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
513 2208 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
514 :
515 2208 : if (len < 0) {
516 0 : odbc_convert_err_set(&dbc->errs, len);
517 0 : return -1;
518 : }
519 :
520 2208 : switch (desttype) {
521 0 : case SYBBINARY:
522 : case SYBVARBINARY:
523 : case SYBIMAGE:
524 : case XSYBBINARY:
525 : case XSYBVARBINARY:
526 : case SYBLONGBINARY:
527 0 : ret = TDS_MIN(destlen, len);
528 0 : memcpy(dest, dres.ib, ret);
529 0 : free(dres.ib);
530 0 : break;
531 2204 : case SYBINT1:
532 : case SYBINT2:
533 : case SYBINT4:
534 : case SYBINT8:
535 : case SYBSINT1:
536 : case SYBUINT1:
537 : case SYBUINT2:
538 : case SYBUINT4:
539 : case SYBUINT8:
540 : case SYB5INT8:
541 : case SYBFLT8:
542 : case SYBREAL:
543 : case SYBBIT:
544 : case SYBBITN:
545 : case SYBMONEY:
546 : case SYBMONEY4:
547 : case SYBDATETIME:
548 : case SYBDATETIME4:
549 : case SYBNUMERIC:
550 : case SYBDECIMAL:
551 : case SYBUNIQUE:
552 : case SYBMSDATE:
553 : case SYBMSTIME:
554 : case SYBMSDATETIME2:
555 : case SYBMSDATETIMEOFFSET:
556 : case SYB5BIGDATETIME:
557 : case SYB5BIGTIME:
558 : case SYBTIME:
559 : case SYBTIMEN:
560 : case SYBDATE:
561 : case SYBDATEN:
562 2204 : memcpy(dest, &dres, len);
563 2204 : ret = len;
564 2204 : break;
565 4 : case SYBCHAR:
566 : case SYBVARCHAR:
567 : case XSYBCHAR:
568 : case XSYBVARCHAR:
569 : case SYBTEXT:
570 4 : ret = (TDS_INT) _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *) dest, destlen);
571 4 : free(dres.c);
572 4 : break;
573 0 : default:
574 0 : tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
575 : ret = -1;
576 : break;
577 :
578 : }
579 : return (ret);
580 : }
581 :
582 : static TDSRET
583 5832 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int index TDS_UNUSED, int offset TDS_UNUSED)
584 : {
585 : TDS_TINYINT ti;
586 : TDS_SMALLINT si;
587 : TDS_INT li;
588 : TDS_INT8 lli;
589 : TDS_SERVER_TYPE desttype, coltype;
590 : SQLLEN col_len;
591 : int data_is_null;
592 : SQLLEN bytes_read;
593 : int converted_data_size;
594 : TDS_CHAR *dataptr;
595 5832 : TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
596 :
597 5832 : tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
598 :
599 5832 : dataptr = bindcol->column_varaddr;
600 :
601 5832 : data_is_null = 0;
602 5832 : col_len = SQL_NULL_DATA;
603 :
604 : /* If a prefix length specified, read the correct amount of data. */
605 :
606 5832 : if (bindcol->bcp_prefix_len > 0) {
607 :
608 2900 : switch (bindcol->bcp_prefix_len) {
609 0 : case 1:
610 0 : memcpy(&ti, dataptr, 1);
611 0 : dataptr += 1;
612 0 : col_len = ti;
613 0 : break;
614 0 : case 2:
615 0 : memcpy(&si, dataptr, 2);
616 0 : dataptr += 2;
617 0 : col_len = si;
618 0 : break;
619 0 : case 4:
620 0 : memcpy(&li, dataptr, 4);
621 0 : dataptr += 4;
622 0 : col_len = li;
623 0 : break;
624 2900 : case 8:
625 2900 : memcpy(&lli, dataptr, 8);
626 2900 : dataptr += 8;
627 2900 : col_len = lli;
628 : if (lli != col_len)
629 : return TDS_FAIL;
630 : break;
631 : }
632 2900 : if (col_len == SQL_NULL_DATA)
633 : data_is_null = 1;
634 : }
635 :
636 : /* if (Max) column length specified take that into consideration. */
637 :
638 5832 : if (bindcol->column_bindlen == SQL_NULL_DATA)
639 : data_is_null = 1;
640 4428 : else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
641 2228 : if (col_len != SQL_NULL_DATA)
642 1100 : col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
643 : else
644 1128 : col_len = bindcol->column_bindlen;
645 : }
646 :
647 5832 : desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
648 :
649 : /* Fixed Length data - this overrides anything else specified */
650 5832 : coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
651 5832 : if (is_fixed_type(coltype)) {
652 1408 : col_len = tds_get_size_by_type(coltype);
653 : }
654 :
655 : /* read the data, finally */
656 :
657 5832 : if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
658 0 : bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
659 :
660 0 : if (col_len != SQL_NULL_DATA)
661 0 : col_len = TDS_MIN(bytes_read, col_len);
662 : else
663 : col_len = bytes_read;
664 : }
665 :
666 5832 : if (data_is_null) {
667 2804 : bindcol->bcp_column_data->datalen = 0;
668 2804 : bindcol->bcp_column_data->is_null = true;
669 : } else {
670 3028 : if ((converted_data_size =
671 3028 : _tdsodbc_dbconvert(dbc, coltype,
672 : dataptr, col_len,
673 3028 : desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
674 : return TDS_FAIL;
675 : }
676 :
677 3028 : bindcol->bcp_column_data->datalen = converted_data_size;
678 3028 : bindcol->bcp_column_data->is_null = false;
679 : }
680 :
681 : return TDS_SUCCESS;
682 : }
683 :
684 : /**
685 : * Get the data for bcp-in from program variables, where the program data
686 : * have been identified as character terminated,
687 : * This is a low-level, internal function. Call it correctly.
688 : */
689 : static SQLLEN
690 0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
691 : {
692 : SQLLEN bufpos;
693 :
694 0 : assert(term_len > 0);
695 :
696 0 : if (term_len == 1 && *term == '\0') /* significant optimization for very common case */
697 0 : return strlen(pdata);
698 :
699 : /* if bufpos becomes negative, we probably failed to find the terminator */
700 0 : for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
701 0 : bufpos++;
702 : }
703 :
704 : assert(bufpos >= 0);
705 : return bufpos;
706 : }
707 :
708 : void
709 1274 : odbc_bcp_free_storage(TDS_DBC *dbc)
710 : {
711 1274 : tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
712 1274 : assert(dbc);
713 :
714 1274 : tds_free_bcpinfo(dbc->bcpinfo);
715 1274 : dbc->bcpinfo = NULL;
716 1274 : }
717 :
|