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 24 : odbc_bcp_init(TDS_DBC *dbc, const ODBC_CHAR *tblname, const ODBC_CHAR *hfile,
89 : const ODBC_CHAR *errfile, int direction _WIDE)
90 : {
91 24 : 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 24 : if (!tblname)
107 0 : ODBCBCP_ERROR_RETURN("HY009");
108 :
109 : /* Free previously allocated storage in dbproc & initialise flags, etc. */
110 :
111 24 : odbc_bcp_free_storage(dbc);
112 :
113 : /*
114 : * Validate other parameters
115 : */
116 24 : if (dbc->tds_socket->conn->tds_version < 0x500)
117 0 : ODBCBCP_ERROR_RETURN("HYC00");
118 :
119 24 : if (direction != BCP_DIRECTION_IN || hfile || errfile)
120 0 : ODBCBCP_ERROR_RETURN("HYC00");
121 :
122 : /* Allocate storage */
123 :
124 24 : dbc->bcpinfo = tds_alloc_bcpinfo();
125 24 : if (dbc->bcpinfo == NULL)
126 0 : ODBCBCP_ERROR_RETURN("HY001");
127 :
128 24 : 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 48 : 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 24 : dbc->bcpinfo->direction = direction;
139 :
140 24 : dbc->bcpinfo->xfer_init = false;
141 24 : dbc->bcpinfo->bind_count = 0;
142 :
143 24 : 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 24 : odbc_bcp_done(TDS_DBC *dbc)
318 : {
319 : int rows_copied;
320 :
321 24 : tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
322 :
323 24 : if (!(dbc->bcpinfo))
324 0 : ODBCBCP_ERROR_DBINT("HY010");
325 :
326 24 : if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
327 0 : 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 612 : 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 612 : 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 612 : if (!dbc->bcpinfo)
367 0 : ODBCBCP_ERROR_RETURN("HY010");
368 :
369 612 : if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
370 0 : ODBCBCP_ERROR_RETURN("HY010");
371 :
372 612 : if (varlen < -1 && varlen != SQL_VARLEN_DATA)
373 0 : ODBCBCP_ERROR_RETURN("HY009");
374 :
375 612 : if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
376 0 : ODBCBCP_ERROR_RETURN("HY009");
377 :
378 1224 : if (vartype != 0 && !is_tds_type_valid(vartype))
379 0 : ODBCBCP_ERROR_RETURN("HY004");
380 :
381 612 : if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen == -1 && !is_fixed_type(vartype)) {
382 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
383 0 : ODBCBCP_ERROR_RETURN("HY009");
384 : }
385 :
386 612 : if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
387 0 : ODBCBCP_ERROR_RETURN("HY009");
388 :
389 612 : if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
390 0 : ODBCBCP_ERROR_RETURN("HY009");
391 :
392 612 : colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1];
393 :
394 : /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
395 : and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
396 612 : if (varaddr == NULL && varlen >= 0) {
397 0 : int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
398 0 : (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
399 : if( !fOK ) {
400 0 : tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
401 : colinfo->column_type, vartype);
402 0 : ODBCBCP_ERROR_RETURN("HY009");
403 : }
404 : }
405 :
406 612 : colinfo->column_varaddr = (char *)varaddr;
407 612 : colinfo->column_bindtype = vartype;
408 612 : colinfo->column_bindlen = varlen;
409 612 : colinfo->bcp_prefix_len = prefixlen;
410 :
411 612 : conv = colinfo->char_conv;
412 612 : if (conv) {
413 136 : TDSCONNECTION *conn = dbc->tds_socket->conn;
414 136 : TDS_SERVER_TYPE desttype = tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size);
415 136 : TDS_SERVER_TYPE srctype = colinfo->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) colinfo->column_bindtype;
416 136 : int src_charset = is_unicode_type(srctype) ? odbc_get_wide_canonic(conn) : dbc->original_charset_num;
417 :
418 136 : colinfo->char_conv = tds_iconv_get_info(conn, src_charset, conv->to.charset.canonic);
419 : }
420 :
421 612 : TDS_ZERO_FREE(colinfo->bcp_terminator);
422 612 : colinfo->bcp_term_len = 0;
423 612 : if (termlen > 0) {
424 0 : if ((colinfo->bcp_terminator = tds_new(TDS_CHAR, termlen)) == NULL)
425 0 : ODBCBCP_ERROR_RETURN("HY001");
426 0 : memcpy(colinfo->bcp_terminator, terminator, termlen);
427 0 : colinfo->bcp_term_len = termlen;
428 : }
429 : }
430 :
431 : static SQLLEN
432 616 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
433 : {
434 616 : if (bindcol->char_conv) {
435 616 : char *orig_dest = dest;
436 :
437 616 : if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
438 : return -1;
439 616 : return dest - orig_dest;
440 : }
441 :
442 0 : if (destlen > srclen)
443 0 : destlen = srclen;
444 0 : memcpy(dest, src, destlen);
445 0 : return destlen;
446 : }
447 :
448 : static TDS_INT
449 3028 : _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len,
450 : int desttype, unsigned char * dest, TDSCOLUMN *bindcol)
451 : {
452 : CONV_RESULT dres;
453 : TDS_INT ret;
454 : TDS_INT len;
455 3028 : TDS_INT destlen = bindcol->column_size;
456 : ODBC_CONVERT_BUF convert_buf;
457 3028 : bool always_convert = false;
458 :
459 3028 : assert(src_len >= 0);
460 3028 : assert(src != NULL);
461 3028 : assert(dest != NULL);
462 3028 : assert(destlen > 0);
463 :
464 3028 : tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n",
465 : dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen);
466 :
467 3028 : switch (srctype) {
468 4 : case SYBMSDATETIME2:
469 4 : convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &convert_buf.dta);
470 4 : convert_buf.dta.time_prec = (destlen - 40) / 2;
471 4 : src = (char *) &convert_buf.dta;
472 4 : break;
473 8 : case SYBDECIMAL:
474 : case SYBNUMERIC:
475 8 : if (convert_numeric2server(&dbc->errs, src, &convert_buf.num) <= 0)
476 : return -1;
477 8 : src = (char *) &convert_buf.num;
478 8 : always_convert = convert_buf.num.scale != bindcol->column_scale;
479 8 : break;
480 : /* TODO intervals */
481 : }
482 :
483 : /* oft times we are asked to convert a data type to itself */
484 3028 : if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
485 820 : if (is_char_type(desttype)) {
486 612 : ret = (TDS_INT) _bcp_iconv_helper (dbc, bindcol, src, src_len, (char *)dest, destlen);
487 : } else {
488 208 : ret = destlen < src_len ? destlen : (TDS_INT) src_len;
489 208 : memcpy(dest, src, ret);
490 : }
491 : return ret;
492 : }
493 :
494 2208 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
495 :
496 2208 : if (is_numeric_type(desttype)) {
497 404 : dres.n.precision = bindcol->column_prec;
498 404 : dres.n.scale = bindcol->column_scale;
499 : }
500 2208 : len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
501 2208 : tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
502 :
503 2208 : if (len < 0) {
504 0 : odbc_convert_err_set(&dbc->errs, len);
505 0 : return -1;
506 : }
507 :
508 2208 : switch (desttype) {
509 0 : case SYBBINARY:
510 : case SYBVARBINARY:
511 : case SYBIMAGE:
512 : case XSYBBINARY:
513 : case XSYBVARBINARY:
514 : case SYBLONGBINARY:
515 0 : ret = TDS_MIN(destlen, len);
516 0 : memcpy(dest, dres.ib, ret);
517 0 : free(dres.ib);
518 0 : break;
519 2204 : case SYBINT1:
520 : case SYBINT2:
521 : case SYBINT4:
522 : case SYBINT8:
523 : case SYBSINT1:
524 : case SYBUINT1:
525 : case SYBUINT2:
526 : case SYBUINT4:
527 : case SYBUINT8:
528 : case SYB5INT8:
529 : case SYBFLT8:
530 : case SYBREAL:
531 : case SYBBIT:
532 : case SYBBITN:
533 : case SYBMONEY:
534 : case SYBMONEY4:
535 : case SYBDATETIME:
536 : case SYBDATETIME4:
537 : case SYBNUMERIC:
538 : case SYBDECIMAL:
539 : case SYBUNIQUE:
540 : case SYBMSDATE:
541 : case SYBMSTIME:
542 : case SYBMSDATETIME2:
543 : case SYBMSDATETIMEOFFSET:
544 : case SYB5BIGDATETIME:
545 : case SYB5BIGTIME:
546 : case SYBTIME:
547 : case SYBTIMEN:
548 : case SYBDATE:
549 : case SYBDATEN:
550 2204 : memcpy(dest, &dres, len);
551 2204 : ret = len;
552 2204 : break;
553 4 : case SYBCHAR:
554 : case SYBVARCHAR:
555 : case XSYBCHAR:
556 : case XSYBVARCHAR:
557 : case SYBTEXT:
558 4 : ret = (TDS_INT) _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *) dest, destlen);
559 4 : free(dres.c);
560 4 : break;
561 0 : default:
562 0 : tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
563 : ret = -1;
564 : break;
565 :
566 : }
567 : return (ret);
568 : }
569 :
570 : static TDSRET
571 5832 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int index TDS_UNUSED, int offset TDS_UNUSED)
572 : {
573 : TDS_TINYINT ti;
574 : TDS_SMALLINT si;
575 : TDS_INT li;
576 : TDS_INT8 lli;
577 : TDS_SERVER_TYPE desttype, coltype;
578 : SQLLEN col_len;
579 : int data_is_null;
580 : SQLLEN bytes_read;
581 : int converted_data_size;
582 : TDS_CHAR *dataptr;
583 5832 : TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
584 :
585 5832 : tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
586 :
587 5832 : dataptr = bindcol->column_varaddr;
588 :
589 5832 : data_is_null = 0;
590 5832 : col_len = SQL_NULL_DATA;
591 :
592 : /* If a prefix length specified, read the correct amount of data. */
593 :
594 5832 : if (bindcol->bcp_prefix_len > 0) {
595 :
596 2900 : switch (bindcol->bcp_prefix_len) {
597 0 : case 1:
598 0 : memcpy(&ti, dataptr, 1);
599 0 : dataptr += 1;
600 0 : col_len = ti;
601 0 : break;
602 0 : case 2:
603 0 : memcpy(&si, dataptr, 2);
604 0 : dataptr += 2;
605 0 : col_len = si;
606 0 : break;
607 0 : case 4:
608 0 : memcpy(&li, dataptr, 4);
609 0 : dataptr += 4;
610 0 : col_len = li;
611 0 : break;
612 2900 : case 8:
613 2900 : memcpy(&lli, dataptr, 8);
614 2900 : dataptr += 8;
615 2900 : col_len = lli;
616 : if (lli != col_len)
617 : return TDS_FAIL;
618 : break;
619 : }
620 2900 : if (col_len == SQL_NULL_DATA)
621 : data_is_null = 1;
622 : }
623 :
624 : /* if (Max) column length specified take that into consideration. */
625 :
626 5832 : if (bindcol->column_bindlen == SQL_NULL_DATA)
627 : data_is_null = 1;
628 4428 : else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
629 2228 : if (col_len != SQL_NULL_DATA)
630 1100 : col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
631 : else
632 1128 : col_len = bindcol->column_bindlen;
633 : }
634 :
635 5832 : desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
636 :
637 : /* Fixed Length data - this overrides anything else specified */
638 5832 : coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
639 5832 : if (is_fixed_type(coltype)) {
640 1408 : col_len = tds_get_size_by_type(coltype);
641 : }
642 :
643 : /* read the data, finally */
644 :
645 5832 : if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
646 0 : bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
647 :
648 0 : if (col_len != SQL_NULL_DATA)
649 0 : col_len = TDS_MIN(bytes_read, col_len);
650 : else
651 : col_len = bytes_read;
652 : }
653 :
654 5832 : if (data_is_null) {
655 2804 : bindcol->bcp_column_data->datalen = 0;
656 2804 : bindcol->bcp_column_data->is_null = true;
657 : } else {
658 3028 : if ((converted_data_size =
659 3028 : _tdsodbc_dbconvert(dbc, coltype,
660 : dataptr, col_len,
661 3028 : desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
662 : return TDS_FAIL;
663 : }
664 :
665 3028 : bindcol->bcp_column_data->datalen = converted_data_size;
666 3028 : bindcol->bcp_column_data->is_null = false;
667 : }
668 :
669 : return TDS_SUCCESS;
670 : }
671 :
672 : /**
673 : * Get the data for bcp-in from program variables, where the program data
674 : * have been identified as character terminated,
675 : * This is a low-level, internal function. Call it correctly.
676 : */
677 : static SQLLEN
678 0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
679 : {
680 : SQLLEN bufpos;
681 :
682 0 : assert(term_len > 0);
683 :
684 0 : if (term_len == 1 && *term == '\0') /* significant optimization for very common case */
685 0 : return strlen(pdata);
686 :
687 : /* if bufpos becomes negative, we probably failed to find the terminator */
688 0 : for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
689 0 : bufpos++;
690 : }
691 :
692 : assert(bufpos >= 0);
693 : return bufpos;
694 : }
695 :
696 : void
697 1254 : odbc_bcp_free_storage(TDS_DBC *dbc)
698 : {
699 1254 : tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
700 1254 : assert(dbc);
701 :
702 1254 : tds_free_bcpinfo(dbc->bcpinfo);
703 1254 : dbc->bcpinfo = NULL;
704 1254 : }
705 :
|